AC_SUBST(SHM_OPEN_LIBS)
if test "x${e_cv_want_wayland_only}" != "xno" || test "x${e_cv_want_wayland_clients}" != "xno";then
- PKG_CHECK_MODULES([WAYLAND], [wayland-server >= 1.8.0 xkbcommon uuid xdg-shell-unstable-v5-server xdg-shell-unstable-v6-server tizen-remote-surface-server scaler-server screenshooter-server tizen-extension-server tizen-launch-server tizen-surface-server tizen-dpms-server eom-server],
+ PKG_CHECK_MODULES([WAYLAND], [wayland-server >= 1.8.0 xkbcommon uuid xdg-shell-unstable-v5-server xdg-shell-unstable-v6-server tizen-remote-surface-server scaler-server screenshooter-server tizen-extension-server tizen-launch-server tizen-surface-server tizen-dpms-server eom-server presentation-time-server],
[
have_wayland=yes
AC_DEFINE_UNQUOTED([HAVE_WAYLAND],[1],[enable wayland support])
BuildRequires: pkgconfig(pixman-1)
BuildRequires: systemd-devel
BuildRequires: pkgconfig(libinput)
+BuildRequires: pkgconfig(presentation-time-server)
Requires: libwayland-extension-server
%if "%{LIBGOMP}" == "use"
Requires: libgomp
endif
ENLIGHTENMENTHEADERS += \
+src/bin/e_presentation_time.h \
src/bin/e_comp_wl_rsm.h \
src/bin/video/e_comp_wl_video.h \
src/bin/video/e_comp_wl_video_buffer.h \
endif
enlightenment_src += \
+src/bin/e_presentation_time.c \
src/bin/e_comp_wl_rsm.c \
src/bin/video/e_comp_wl_video.c \
src/bin/video/e_comp_wl_video_buffer.c \
state->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
state->buffer_viewport.surface.width = -1;
state->buffer_viewport.changed = 0;
+
+ e_presentation_time_container_init(&state->presentation_container);
}
static void
if (state->buffer) wl_list_remove(&state->buffer_destroy_listener.link);
state->buffer = NULL;
+
+ e_presentation_time_container_finish(&state->presentation_container);
}
static void
state->frames);
state->frames = NULL;
+ e_presentation_time_container_feedback_discard(&ec->comp_data->presentation_container);
+ e_presentation_time_container_feedback_merge(&ec->comp_data->presentation_container,
+ &ec->comp_data->pending.presentation_container);
+
buffer = e_pixmap_resource_get(ec->pixmap);
/* put state damages into surface */
ec->comp_data->scaler.buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
ec->comp_data->scaler.buffer_viewport.surface.width = -1;
+ e_presentation_time_container_init(&ec->comp_data->presentation_container);
+
E_Comp_Client_Data *p_cdata = e_pixmap_cdata_get(ec->pixmap);
EINA_SAFETY_ON_NULL_GOTO(p_cdata, end);
ec->comp_data->viewport_transform = NULL;
}
+ e_presentation_time_container_finish(&ec->comp_data->presentation_container);
+
e_pixmap_cdata_set(ec->pixmap, NULL);
E_FREE(ec->comp_data);
e_comp_wl_viewport_init();
e_comp_wl_capture_init();
_e_comp_wl_move_resize_init();
+ e_presentation_time_init();
/* add event handlers to catch E events */
E_LIST_HANDLER_APPEND(handlers, E_EVENT_SCREEN_CHANGE, _e_comp_wl_cb_randr_change, NULL);
E_FREE_LIST(hooks, e_client_hook_del);
_e_comp_wl_gl_shutdown();
+ e_presentation_time_shutdown();
e_comp_wl_capture_shutdown();
e_comp_wl_viewport_shutdown();
e_comp_wl_video_shutdown();
E_Comp_Wl_Buffer_Viewport buffer_viewport;
Eina_Bool new_attach : 1;
Eina_Bool has_data : 1;
+
+ E_Presentation_Time_Container presentation_container;
};
struct _E_Comp_Wl_Subsurf_Data
E_Comp_Wl_Surface_State pending;
Eina_List *frames;
+ E_Presentation_Time_Container presentation_container;
struct
{
# include <pixman.h>
# include <wayland-tbm-server.h>
#include "services/e_service_quickpanel.h"
+#include <presentation-time-server-protocol.h>
#ifndef CLEAR
#define CLEAR(x) memset(&(x), 0, sizeof (x))
hwc->hwc_windows = eina_list_remove(hwc->hwc_windows, hwc_window);
+ e_presentation_time_container_finish(&hwc_window->presentation_container);
+
output = hwc->output;
EINA_SAFETY_ON_NULL_GOTO(hwc->output, done);
_e_hwc_window_commit_data_acquire_device(E_Hwc_Window *hwc_window)
{
E_Hwc_Window_Commit_Data *commit_data = NULL;
+
EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, NULL);
commit_data = E_NEW(E_Hwc_Window_Commit_Data, 1);
hwc->hwc_windows = eina_list_append(hwc->hwc_windows, hwc_window);
+ e_presentation_time_container_init(&hwc_window->presentation_container);
+
EHWINF("is created on eout:%p, zone_id:%d video:%d cursor:%d",
hwc_window->ec, hwc_window->hwc, hwc_window, hwc->output, ec->zone->id,
hwc_window->is_video, hwc_window->is_cursor);
return EINA_TRUE;
}
+EINTERN void
+e_hwc_window_presentation_time_feedback_take(E_Hwc_Window *hwc_window,
+ E_Presentation_Time_Container *container)
+{
+ EINA_SAFETY_ON_NULL_RETURN(hwc_window);
+ EINA_SAFETY_ON_NULL_RETURN(container);
+
+ e_presentation_time_container_feedback_merge(&hwc_window->presentation_container,
+ container);
+}
+
+EINTERN void
+e_hwc_window_presentation_time_feedback_present(E_Hwc_Window *hwc_window,
+ uint64_t sequence,
+ uint64_t tv_sec,
+ uint64_t tv_usec)
+{
+ E_Output *output;
+ unsigned int flags =
+ WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
+
+ EINA_SAFETY_ON_NULL_RETURN(hwc_window);
+
+ if (!eina_list_count(hwc_window->presentation_container.presentation_feedbacks))
+ return;
+
+ EINA_SAFETY_ON_NULL_GOTO(hwc_window->hwc, discard);
+
+ output = hwc_window->hwc->output;
+ EINA_SAFETY_ON_NULL_GOTO(output, discard);
+
+ if ((sequence) || (tv_sec) || (tv_usec))
+ flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
+
+ if (!hwc_window->is_target)
+ flags |= WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
+
+ e_presentation_time_container_feedback_present(&hwc_window->presentation_container,
+ output,
+ tv_sec,
+ tv_usec * 1000,
+ sequence,
+ flags);
+ return;
+
+discard:
+ e_presentation_time_container_feedback_discard(&hwc_window->presentation_container);
+}
+
+EINTERN void
+e_hwc_window_presentation_time_feedback_discard(E_Hwc_Window *hwc_window)
+{
+ EINA_SAFETY_ON_NULL_RETURN(hwc_window);
+
+ e_presentation_time_container_feedback_discard(&hwc_window->presentation_container);
+}
+
EINTERN Eina_Bool
e_hwc_window_commit_data_release(E_Hwc_Window *hwc_window)
{
Eina_Bool on_rendered_target;
unsigned int restriction;
+
+ E_Presentation_Time_Container presentation_container;
};
struct _E_Hwc_Window_Target
EINTERN Eina_Bool e_hwc_window_pp_rendered_window_update(E_Hwc_Window *hwc_window);
EINTERN Eina_Bool e_hwc_window_pp_commit_data_acquire(E_Hwc_Window *hwc_window, Eina_Bool pp_hwc_mode);
+EINTERN void e_hwc_window_presentation_time_feedback_present(E_Hwc_Window *hwc_window, uint64_t sequence, uint64_t tv_sec, uint64_t tv_usec);
+EINTERN void e_hwc_window_presentation_time_feedback_discard(E_Hwc_Window *hwc_window);
+EINTERN void e_hwc_window_presentation_time_feedback_take(E_Hwc_Window *hwc_window, E_Presentation_Time_Container *container);
+
#endif // E_HWC_WINDOW_H
#endif
while (0)
typedef struct _E_Hwc_Windows_Pp_Data E_Hwc_Windows_Pp_Data;
+typedef struct _E_Hwc_Windows_Buffer_Comp_Info E_Hwc_Windows_Buffer_Comp_Info;
struct _E_Hwc_Windows_Pp_Data
{
E_Output_Display_Mode mode;
};
+struct _E_Hwc_Windows_Buffer_Comp_Info
+{
+ E_Presentation_Time_Container presentation_container;
+};
+
static Eina_Bool ehws_trace = EINA_FALSE;
static Eina_Bool ehws_dump_enable = EINA_FALSE;
static uint64_t ehws_rendered_windows_key;
static uint64_t ehws_rendered_buffers_key;
#define EHWS_RENDERED_BUFFERS_KEY (unsigned long)(&ehws_rendered_buffers_key)
+static uint64_t ehws_comp_buffer_info_key;
+#define EHWS_BUFFER_COMP_INFO_KEY (unsigned long)(&ehws_comp_buffer_info_key)
+
static Eina_Bool _e_hwc_windows_target_window_queue_set(E_Hwc_Window_Target *target_hwc_window);
static Eina_Bool _e_hwc_windows_pp_output_data_commit(E_Hwc *hwc, E_Hwc_Window_Commit_Data *data);
static Eina_Bool _e_hwc_windows_pp_window_commit(E_Hwc *hwc, E_Hwc_Window *hwc_window);
return aligned_width;
}
+static void
+_e_hwc_windows_buffer_comp_info_free(void *data)
+{
+ E_Hwc_Windows_Buffer_Comp_Info *comp_info;
+
+ comp_info = (E_Hwc_Windows_Buffer_Comp_Info *)data;
+ if (!comp_info) return;
+
+ e_presentation_time_container_finish(&comp_info->presentation_container);
+
+ E_FREE(comp_info);
+}
+
+static E_Hwc_Windows_Buffer_Comp_Info *
+_e_hwc_windows_buffer_comp_info_get(tbm_surface_h tbm_surface)
+{
+ E_Hwc_Windows_Buffer_Comp_Info *comp_info = NULL;
+
+ tbm_surface_internal_get_user_data(tbm_surface, EHWS_BUFFER_COMP_INFO_KEY,
+ (void**)&comp_info);
+
+ if (comp_info) return comp_info;
+
+ comp_info = E_NEW(E_Hwc_Windows_Buffer_Comp_Info, 1);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(comp_info, NULL);
+
+ e_presentation_time_container_init(&comp_info->presentation_container);
+
+ tbm_surface_internal_add_user_data(tbm_surface, EHWS_BUFFER_COMP_INFO_KEY,
+ _e_hwc_windows_buffer_comp_info_free);
+
+ tbm_surface_internal_set_user_data(tbm_surface, EHWS_BUFFER_COMP_INFO_KEY,
+ comp_info);
+
+ return comp_info;
+}
+
+static void
+_e_hwc_windows_presentation_feedback_take(E_Hwc_Window *hwc_window)
+{
+ E_Presentation_Time_Container *container = NULL;
+
+ if (hwc_window->is_target)
+ {
+ E_Hwc_Windows_Buffer_Comp_Info *buffer_comp_info;
+
+ if (!hwc_window->buffer.tsurface) return;
+
+ buffer_comp_info = _e_hwc_windows_buffer_comp_info_get(hwc_window->buffer.tsurface);
+ if (!buffer_comp_info) return;
+
+ container = &buffer_comp_info->presentation_container;
+ }
+ else
+ {
+ E_Client *ec;
+
+ ec = hwc_window->ec;
+ if (!ec) return;
+ if (!ec->comp_data) return;
+
+ container = &ec->comp_data->presentation_container;
+ }
+
+ if (!container) return;
+
+ e_hwc_window_presentation_time_feedback_take(hwc_window, container);
+}
+
static void
_e_hwc_windows_commit_data_release(E_Hwc *hwc, int sequence,
unsigned int tv_sec, unsigned int tv_usec)
const Eina_List *l;
E_Hwc_Window *hwc_window;
+ e_hwc_window_presentation_time_feedback_present(((E_Hwc_Window *)hwc->target_hwc_window),
+ sequence,
+ tv_sec,
+ tv_usec);
+
EINA_LIST_FOREACH(hwc->hwc_windows, l, hwc_window)
{
if (!hwc_window->commit_data) continue;
+
+ e_hwc_window_presentation_time_feedback_present(hwc_window, sequence, tv_sec, tv_usec);
+
if (e_hwc_window_is_video(hwc_window) && hwc_window->ec)
e_client_video_commit_data_release(hwc_window->ec, sequence, tv_sec, tv_usec);
temp = e_hwc_window_commit_data_acquire(hwc_window);
if (!temp) continue;
+ _e_hwc_windows_presentation_feedback_take(hwc_window);
+
if (ehws_dump_enable)
e_hwc_window_commit_data_buffer_dump(hwc_window);
Eina_List *l;
Eina_Bool ret = EINA_FALSE;
+ e_hwc_window_presentation_time_feedback_discard(((E_Hwc_Window *)hwc->target_hwc_window));
+
EINA_LIST_FOREACH(hwc->hwc_windows, l, hwc_window)
{
if (hwc->pp_set)
EHWSTRACE("!!!!!!!! HWC OffScreen Commit !!!!!!!!", NULL, hwc);
-
/* send frame event enlightenment doesn't send frame event in nocomp */
if (hwc_window->ec)
e_pixmap_image_clear(hwc_window->ec->pixmap, 1);
+ e_hwc_window_presentation_time_feedback_discard(hwc_window);
+
e_hwc_window_commit_data_release(hwc_window);
}
}
E_Hwc_Window_Target *target_hwc_window;
E_Hwc_Window *hwc_window = NULL;
E_Hwc_Window_Queue_Buffer *queue_buffer;
+ E_Hwc_Windows_Buffer_Comp_Info *buffer_comp_info;
tdm_hwc *thwc = NULL;
tdm_region fb_damage;
if (hwc_window->buffer.tsurface &&
hwc_window->buffer.tsurface != hwc_window->display.buffer.tsurface)
{
+ buffer_comp_info = _e_hwc_windows_buffer_comp_info_get(hwc_window->buffer.tsurface);
+ if (buffer_comp_info)
+ e_hwc_window_presentation_time_feedback_take(hwc_window,
+ &buffer_comp_info->presentation_container);
+
if (hwc_window->buffer.queue)
{
queue_buffer = e_hwc_window_queue_buffer_find(hwc_window->buffer.queue, hwc_window->buffer.tsurface);
{
queue_buffer = e_hwc_window_queue_buffer_find(hwc_window->buffer.queue, hwc_window->buffer.tsurface);
if (queue_buffer)
- e_hwc_window_queue_buffer_release(hwc_window->buffer.queue, queue_buffer);
+ {
+ E_Hwc_Windows_Buffer_Comp_Info *buffer_comp_info;
+
+ buffer_comp_info = _e_hwc_windows_buffer_comp_info_get(hwc_window->buffer.tsurface);
+ if (buffer_comp_info)
+ e_hwc_window_presentation_time_feedback_take(hwc_window,
+ &buffer_comp_info->presentation_container);
+
+ e_hwc_window_queue_buffer_release(hwc_window->buffer.queue, queue_buffer);
+ }
}
e_hwc_window_buffer_set(hwc_window, NULL, NULL);
E_Hwc_Window *hwc_window = NULL;
E_Comp_Wl_Buffer_Ref *buffer_ref = NULL;
E_Comp_Wl_Buffer *buffer = NULL;
+ E_Hwc_Windows_Buffer_Comp_Info *buffer_comp_info;
Eina_List *rendered_buffers = NULL;
Eina_List *rendered_windows = NULL;
Eina_List *visible_windows = NULL;
e_hwc_windows_rendered_window_add(hwc_window);
}
+ buffer_comp_info = _e_hwc_windows_buffer_comp_info_get(target_hwc_window->dequeued_tsurface);
+ if (!buffer_comp_info)
+ EHWSERR("fail to get buffer_comp_info tsurface:%p", target_hwc_window->hwc, target_hwc_window->dequeued_tsurface);
+
/* all ecs have been composited so we can attach a list of composited e_hwc_windows to the surface
* which contains their ecs composited */
rendered_windows = eina_list_clone(target_hwc_window->rendered_windows);
ec = hwc_window->ec;
if (!ec) continue;
+ if (buffer_comp_info && ec->comp_data)
+ e_presentation_time_container_feedback_merge(&buffer_comp_info->presentation_container,
+ &ec->comp_data->presentation_container);
+
buffer = e_pixmap_ref_resource_get(ec->pixmap);
if (!buffer)
buffer = _e_hwc_windows_comp_wl_buffer_get(hwc_window);
#include "e_hwc_windows.h"
#include "e_hwc_window.h"
#include "e_hwc_window_queue.h"
+#include "e_presentation_time.h"
#include "e_comp_wl.h"
#include "e_comp_wl_subsurface.h"
#include "e_comp_wl_data.h"
}
return;
}
+ else if (eina_streq(argv[2], "prstt"))
+ {
+ if (!_e_info_client_eldbus_message_with_args("trace_message_prstt", NULL, "i", onoff))
+ {
+ printf("_e_info_client_eldbus_message_with_args error");
+ }
+ return;
+ }
}
arg_err:
return reply;
}
+
static Eldbus_Message *
e_info_server_cb_serial_trace_message(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
return reply;
}
+static Eldbus_Message *
+e_info_server_cb_prstt_trace_message(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
+{
+ Eldbus_Message *reply = eldbus_message_method_return_new(msg);
+ uint32_t on;
+
+ if (!eldbus_message_arguments_get(msg, "i", &on))
+ {
+ ERR("Error getting arguments.");
+ return reply;
+ }
+
+ if (on == 0 || on == 1)
+ e_presentation_time_trace_debug(on);
+
+ return reply;
+}
+
static Eldbus_Message *
e_info_server_cb_hwc(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
{ "output_mode", ELDBUS_ARGS({SIGNATURE_OUTPUT_MODE_CLIENT, "output mode"}), ELDBUS_ARGS({"a("SIGNATURE_OUTPUT_MODE_SERVER")", "array of ec"}), _e_info_server_cb_output_mode, 0 },
{ "trace_message_hwc", ELDBUS_ARGS({"i", "trace_message_hwc"}), NULL, e_info_server_cb_hwc_trace_message, 0},
{ "trace_message_serial", ELDBUS_ARGS({"i", "trace_message_serial"}), NULL, e_info_server_cb_serial_trace_message, 0},
+ { "trace_message_prstt", ELDBUS_ARGS({"i", "trace_message_presentation_time"}), NULL, e_info_server_cb_prstt_trace_message, 0},
{ "hwc", ELDBUS_ARGS({"i", "hwc"}), NULL, e_info_server_cb_hwc, 0},
{ "show_plane_state", NULL, NULL, e_info_server_cb_show_plane_state, 0},
{ "show_pending_commit", NULL, ELDBUS_ARGS({"a("VALUE_TYPE_FOR_PENDING_COMMIT")", "array of pending commit"}), e_info_server_cb_show_pending_commit, 0},
"\tenlightenment_info -trace hwc 1\n" \
"\tenlightenment_info -trace hwc 0\n" \
"\tenlightenment_info -trace serial 1\n" \
- "\tenlightenment_info -trace serial 0\n"
+ "\tenlightenment_info -trace serial 0\n" \
+ "\tenlightenment_info -trace prstt 1\n" \
+ "\tenlightenment_info -trace prstt 0\n"
/* -------------------------------------------------------------------------- */
/* HWC WINS */
if (only_free == EINA_FALSE)
{
- /* release the helded buffer by e_client */
if (cp->client->comp_data)
- e_comp_wl_buffer_reference(&cp->client->comp_data->buffer_ref, NULL);
+ {
+ /* release the helded buffer by e_client */
+ e_comp_wl_buffer_reference(&cp->client->comp_data->buffer_ref, NULL);
+ e_presentation_time_container_feedback_discard(&cp->client->comp_data->presentation_container);
+ }
+
/* composite object clear */
e_comp_object_clear(cp->client->frame);
--- /dev/null
+#include "e.h"
+#include <presentation-time-server-protocol.h>
+#include <tizen-extension-server-protocol.h>
+
+
+#define PRSTT_TRACE(f, ec, x... ) \
+ do \
+ { \
+ if (prstt_trace) \
+ { \
+ if (ec) \
+ { \
+ INF("EWL|%20.20s|w:0x%08zx|ec:%8p|"f, \
+ "PRESENTATION-TIME", \
+ (e_client_util_win_get(ec)), \
+ (ec), \
+ ##x); \
+ } \
+ else \
+ { \
+ INF("EWL|%20.20s| | |"f,\
+ "PRESENTATION-TIME",##x); \
+ } \
+ } \
+ } \
+ while (0)
+
+static E_Presentation_Time *_presentation = NULL;
+static Eina_Bool prstt_trace = EINA_FALSE;
+
+static const char *
+_get_clock_id_string(clockid_t clock_id)
+{
+ switch(clock_id) {
+ case CLOCK_REALTIME: return "CLOCK_REALTIME";
+ case CLOCK_MONOTONIC: return "CLOCK_MONOTONIC";
+ case CLOCK_PROCESS_CPUTIME_ID: return "CLOCK_PROCESS_CPUTIME_ID";
+ case CLOCK_THREAD_CPUTIME_ID: return "CLOCK_THREAD_CPUTIME_ID";
+ default: return "Unkown";
+ }
+
+ return "Unknown";
+}
+
+static const char *
+_get_flags_string(uint32_t flags)
+{
+ static char string[256];
+ uint32_t remain_flags = flags;
+
+ memset(string, 0, sizeof (string));
+
+ strncat(string, "|", 1);
+
+ if (flags & WP_PRESENTATION_FEEDBACK_KIND_VSYNC)
+ {
+ remain_flags &= ~WP_PRESENTATION_FEEDBACK_KIND_VSYNC;
+ strncat(string, "VSYNC|", 7);
+ }
+
+ if (flags & WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK)
+ {
+ remain_flags &= ~WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
+ strncat(string, "HW_CLOCK|", 9);
+ }
+
+ if (flags & WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION)
+ {
+ remain_flags &= ~WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
+ strncat(string, "HW_COMPLETION|", 14);
+ }
+
+ if (flags & WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY)
+ {
+ remain_flags &= ~WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
+ strncat(string, "ZERO_COPY|", 10);
+ }
+
+ if (remain_flags)
+ strncat(string, "UNKOWN_FLAGS|", 13);
+
+ return string;
+}
+
+EINTERN void
+e_presentation_time_container_feedback_merge(E_Presentation_Time_Container *inout,
+ E_Presentation_Time_Container *input)
+{
+ E_Presentation_Time_Feedback *feedback = NULL;
+ Eina_List *l, *ll;
+
+ EINA_SAFETY_ON_NULL_RETURN(inout);
+ EINA_SAFETY_ON_NULL_RETURN(input);
+
+ /* remove list in feedback_set */
+ EINA_LIST_FOREACH_SAFE(input->presentation_feedbacks, l, ll, feedback)
+ e_presentation_time_container_feedback_set(inout, feedback);
+}
+
+static void
+_presentation_feedback_cb_resource_destroy(struct wl_resource *feedback_resource)
+{
+ E_Presentation_Time_Feedback *feedback;
+
+ feedback = wl_resource_get_user_data(feedback_resource);
+ if (!feedback) return;
+
+ if (feedback->container)
+ {
+ feedback->container->presentation_feedbacks =
+ eina_list_remove(feedback->container->presentation_feedbacks,
+ feedback);
+ }
+
+ PRSTT_TRACE("feedback:%p Destroy", NULL, feedback);
+
+ E_FREE(feedback);
+}
+
+EINTERN Eina_Bool
+e_presentation_time_container_feedback_set(E_Presentation_Time_Container *container,
+ E_Presentation_Time_Feedback *feedback)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(container, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(feedback, EINA_FALSE);
+
+ if (feedback->container)
+ {
+ feedback->container->presentation_feedbacks =
+ eina_list_remove(feedback->container->presentation_feedbacks,
+ feedback);
+ }
+
+ if (!eina_list_data_find(container->presentation_feedbacks, feedback))
+ {
+ container->presentation_feedbacks =
+ eina_list_prepend(container->presentation_feedbacks,
+ feedback);
+ }
+
+ PRSTT_TRACE("feedback:%p Set container:%p", NULL, feedback, container);
+
+ feedback->container = container;
+
+ return EINA_TRUE;
+}
+
+EINTERN Eina_Bool
+e_presentation_time_container_feedback_unset(E_Presentation_Time_Container *container,
+ E_Presentation_Time_Feedback *feedback)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(container, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(feedback, EINA_FALSE);
+
+ if (feedback->container)
+ {
+ feedback->container->presentation_feedbacks =
+ eina_list_remove(feedback->container->presentation_feedbacks,
+ feedback);
+
+ PRSTT_TRACE("feedback:%p Unset container:%p", NULL, feedback, feedback->container);
+ }
+
+ feedback->container = NULL;
+
+ return EINA_TRUE;
+}
+
+static void
+_presentation_feedback(struct wl_client *client,
+ struct wl_resource *presentation_resource,
+ struct wl_resource *surface_resource,
+ uint32_t callback)
+{
+ E_Client *ec;
+ E_Presentation_Time_Feedback *feedback;
+
+ ec = wl_resource_get_user_data(surface_resource);
+ if (!ec) return;
+ if (e_object_is_del(E_OBJECT(ec))) return;
+
+ feedback = E_NEW(E_Presentation_Time_Feedback, 1);
+ if (!feedback)
+ {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ feedback->resource = wl_resource_create(client,
+ &wp_presentation_feedback_interface,
+ 1, callback);
+ if (!feedback->resource)
+ {
+ wl_client_post_no_memory(client);
+ E_FREE(feedback);
+ return;
+ }
+
+ wl_resource_set_implementation(feedback->resource, NULL, feedback,
+ _presentation_feedback_cb_resource_destroy);
+
+ PRSTT_TRACE("feedback:%p Create", NULL, feedback);
+
+ e_presentation_time_container_feedback_set(&ec->comp_data->pending.presentation_container,
+ feedback);
+}
+
+static void
+_presentation_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wp_presentation_interface presentation_implementation = {
+ _presentation_destroy,
+ _presentation_feedback
+};
+
+static void
+_presentation_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource;
+ E_Presentation_Time *presentation;
+
+ presentation = _presentation;
+
+ resource = wl_resource_create(client, &wp_presentation_interface, version, id);
+ if (!resource)
+ {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &presentation_implementation,
+ presentation, NULL);
+
+
+ PRSTT_TRACE("send clock id:%d(%s)", NULL, presentation->clock_id,
+ _get_clock_id_string(presentation->clock_id));
+
+ wp_presentation_send_clock_id(resource, presentation->clock_id);
+}
+
+EINTERN Eina_Bool
+e_presentation_time_init(void)
+{
+ E_Presentation_Time *presentation;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl->wl.disp, EINA_FALSE);
+
+ if (_presentation) return EINA_TRUE;
+
+ presentation = E_NEW(E_Presentation_Time, 1);
+ EINA_SAFETY_ON_NULL_GOTO(presentation, fail);
+
+ presentation->global = wl_global_create(e_comp_wl->wl.disp,
+ &wp_presentation_interface,
+ 1,
+ NULL,
+ _presentation_cb_bind);
+ EINA_SAFETY_ON_NULL_GOTO(presentation->global, fail);
+
+ presentation->clock_id = CLOCK_MONOTONIC;
+ _presentation = presentation;
+
+ return EINA_TRUE;
+
+fail:
+ if (presentation->global)
+ wl_global_destroy(presentation->global);
+
+ if (presentation)
+ E_FREE(presentation);
+
+ return EINA_FALSE;
+}
+
+EINTERN void
+e_presentation_time_shutdown(void)
+{
+ E_Presentation_Time *presentation;
+
+ presentation = _presentation;
+ if (!presentation) return;
+
+ wl_global_destroy(presentation->global);
+ E_FREE(presentation);
+
+ _presentation = NULL;
+}
+
+static void
+_e_presentation_time_feedback_discard(E_Presentation_Time_Feedback *feedback)
+{
+ EINA_SAFETY_ON_NULL_RETURN(feedback);
+ EINA_SAFETY_ON_NULL_RETURN(feedback->resource);
+
+ PRSTT_TRACE("feedback:%p Discard", NULL, feedback);
+
+ wp_presentation_feedback_send_discarded(feedback->resource);
+ wl_resource_destroy(feedback->resource);
+}
+
+static struct wl_resource *
+_presentation_feedback_output_find(E_Presentation_Time_Feedback *feedback, const char *id)
+{
+ E_Comp_Wl_Output *wl_output = NULL;
+ struct wl_resource *wl_output_resource = NULL;
+ Eina_Bool found = EINA_FALSE;
+ struct wl_client *wl_client;
+ Eina_List *l;
+
+ if (!e_comp_wl) return NULL;
+
+ wl_client = wl_resource_get_client(feedback->resource);
+ if (!wl_client) return NULL;
+
+ EINA_LIST_FOREACH(e_comp_wl->outputs, l, wl_output)
+ {
+ if(!e_util_strcmp(wl_output->id, id))
+ {
+ found = EINA_TRUE;
+ break;
+ }
+ }
+
+ if (!found) return NULL;
+
+ EINA_LIST_FOREACH(wl_output->resources, l, wl_output_resource)
+ {
+ if (wl_resource_get_client(wl_output_resource) == wl_client)
+ return wl_output_resource;
+ }
+
+ return NULL;
+}
+
+static void
+_e_presentation_time_feedback_present(E_Presentation_Time_Feedback *feedback,
+ E_Output *output,
+ uint64_t tv_sec,
+ uint32_t tv_nsec,
+ uint64_t seq,
+ uint32_t flags)
+{
+ struct wl_resource *wl_output;
+ uint32_t refresh_nsec = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN(feedback);
+ EINA_SAFETY_ON_NULL_RETURN(feedback->resource);
+ EINA_SAFETY_ON_NULL_GOTO(output, discard);
+
+ wl_output = _presentation_feedback_output_find(feedback, output->id);
+ if (wl_output)
+ wp_presentation_feedback_send_sync_output(feedback->resource, wl_output);
+
+ if (output->config.mode.refresh > 0)
+ refresh_nsec = 1000000000000LL / output->config.mode.refresh;
+
+ PRSTT_TRACE("feedback:%p Present tv_sec:%llu tv_nsec:%u refresh_nsec:%u seq:%llu flags:0x%x(%s)",
+ NULL, feedback, tv_sec, tv_nsec, refresh_nsec, seq, flags, _get_flags_string(flags));
+
+ wp_presentation_feedback_send_presented(feedback->resource,
+ tv_sec >> 32, tv_sec & 0xffffffff,
+ tv_nsec,
+ refresh_nsec,
+ seq >> 32, seq & 0xffffffff,
+ flags);
+ wl_resource_destroy(feedback->resource);
+
+ return;
+
+discard:
+ _e_presentation_time_feedback_discard(feedback);
+}
+
+EINTERN void
+e_presentation_time_container_feedback_discard(E_Presentation_Time_Container *container)
+{
+ E_Presentation_Time_Feedback *feedback = NULL;
+ Eina_List *l, *ll;
+
+ EINA_SAFETY_ON_NULL_RETURN(container);
+
+ /* remove list in resource_destroy callback */
+ EINA_LIST_FOREACH_SAFE(container->presentation_feedbacks, l, ll, feedback)
+ _e_presentation_time_feedback_discard(feedback);
+}
+
+EINTERN void
+e_presentation_time_container_feedback_present(E_Presentation_Time_Container *container,
+ E_Output *output,
+ uint64_t tv_sec,
+ uint32_t tv_nsec,
+ uint64_t seq,
+ uint32_t flags)
+{
+ E_Presentation_Time_Feedback *feedback = NULL;
+ Eina_List *l, *ll;
+
+ EINA_SAFETY_ON_NULL_GOTO(output, discard);
+
+ /* remove list in resource_destroy callback */
+ EINA_LIST_FOREACH_SAFE(container->presentation_feedbacks, l, ll, feedback)
+ _e_presentation_time_feedback_present(feedback, output, tv_sec, tv_nsec,
+ seq, flags);
+
+ return;
+
+discard:
+ e_presentation_time_container_feedback_discard(container);
+}
+
+EINTERN void
+e_presentation_time_container_init(E_Presentation_Time_Container *container)
+{
+ EINA_SAFETY_ON_NULL_RETURN(container);
+}
+
+EINTERN void
+e_presentation_time_container_finish(E_Presentation_Time_Container *container)
+{
+ E_Presentation_Time_Feedback *feedback = NULL;
+ Eina_List *l, *ll;
+
+ if (!container) return;
+
+ /* remove list in resource_destroy callback */
+ EINA_LIST_FOREACH_SAFE(container->presentation_feedbacks, l, ll, feedback)
+ _e_presentation_time_feedback_discard(feedback);
+}
+
+EINTERN void
+e_presentation_time_trace_debug(Eina_Bool onoff)
+{
+ if (onoff == prstt_trace) return;
+ prstt_trace = onoff;
+ INF("Presentation Time Debug is %s", onoff?"ON":"OFF");
+}
--- /dev/null
+#ifdef E_TYPEDEFS
+
+typedef struct _E_Presentation_Time E_Presentation_Time;
+typedef struct _E_Presentation_Time_Feedback E_Presentation_Time_Feedback;
+typedef struct _E_Presentation_Time_Container E_Presentation_Time_Container;
+
+struct _E_Presentation_Time_Container
+{
+ Eina_List *presentation_feedbacks;
+};
+
+#else
+#ifndef E_PRESENTATION_TIME_H
+#define E_PRESENTATION_TIME_H
+
+struct _E_Presentation_Time
+{
+ struct wl_global *global;
+ clockid_t clock_id;
+};
+
+struct _E_Presentation_Time_Feedback
+{
+ struct wl_resource *resource;
+
+ E_Presentation_Time_Container *container;
+};
+
+EINTERN Eina_Bool e_presentation_time_init(void);
+EINTERN void e_presentation_time_shutdown(void);
+
+EINTERN void e_presentation_time_container_init(E_Presentation_Time_Container *container);
+EINTERN void e_presentation_time_container_finish(E_Presentation_Time_Container *container);
+
+EINTERN Eina_Bool e_presentation_time_container_feedback_set(E_Presentation_Time_Container *container,
+ E_Presentation_Time_Feedback *feedback);
+EINTERN Eina_Bool e_presentation_time_container_feedback_unset(E_Presentation_Time_Container *container,
+ E_Presentation_Time_Feedback *feedback);
+EINTERN void e_presentation_time_container_feedback_discard(E_Presentation_Time_Container *container);
+EINTERN void e_presentation_time_container_feedback_present(E_Presentation_Time_Container *container,
+ E_Output *output,
+ uint64_t tv_sec,
+ uint32_t tv_nsec,
+ uint64_t seq,
+ uint32_t flags);
+EINTERN void e_presentation_time_container_feedback_merge(E_Presentation_Time_Container *inout,
+ E_Presentation_Time_Container *input);
+
+EINTERN void e_presentation_time_trace_debug(Eina_Bool onoff);
+
+#endif // E_PRESENTATION_TIME_H
+#endif