implement presentation-time protocol in e_hwc_windows
authorChangyeon Lee <cyeon.lee@samsung.com>
Tue, 29 Oct 2019 10:14:12 +0000 (19:14 +0900)
committerGwanglim Lee <gl77.lee@samsung.com>
Wed, 27 Nov 2019 08:56:15 +0000 (17:56 +0900)
Change-Id: I6f0907f4e4b09469e4ad1103e6fce6cd28eaa399

15 files changed:
configure.ac
packaging/enlightenment.spec
src/bin/Makefile.mk
src/bin/e_comp_wl.c
src/bin/e_comp_wl.h
src/bin/e_hwc_window.c
src/bin/e_hwc_window.h
src/bin/e_hwc_windows.c
src/bin/e_includes.h
src/bin/e_info_client.c
src/bin/e_info_server.c
src/bin/e_info_shared_types.h
src/bin/e_pixmap.c
src/bin/e_presentation_time.c [new file with mode: 0644]
src/bin/e_presentation_time.h [new file with mode: 0644]

index 5c595e7f7d3de5845b30b6180aa33d93bf22006b..aeb22d1b49032d37e54b7d7510137ca5c4146dd5 100755 (executable)
@@ -367,7 +367,7 @@ AC_MSG_RESULT([${have_shm_open}])
 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])
index 42689865f73ca56f08cbb463d18a632f39b845fc..2bb6181009880ab013d7401bbf22926ad552eda6 100644 (file)
@@ -53,6 +53,7 @@ BuildRequires:  pkgconfig(libsmack)
 BuildRequires:  pkgconfig(pixman-1)
 BuildRequires:  systemd-devel
 BuildRequires:  pkgconfig(libinput)
+BuildRequires:  pkgconfig(presentation-time-server)
 Requires:       libwayland-extension-server
 %if "%{LIBGOMP}" == "use"
 Requires:       libgomp
index c09305156aa71100c1e5be8d82bf3906754010f7..ad5117b8c110370541342ba168bfd069f5b2e0d8 100644 (file)
@@ -103,6 +103,7 @@ src/bin/e_comp_wl_tbm.h
 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 \
@@ -222,6 +223,7 @@ src/bin/e_comp_wl_tbm.c
 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 \
index 12ff69e696c7dcc4c94ce1c6ea9ea28e917bf6f2..960185cc9acf42aa113aae0ece25e48ab55c3560 100644 (file)
@@ -2177,6 +2177,8 @@ _e_comp_wl_surface_state_init(E_Comp_Wl_Surface_State *state, int w, int h)
    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
@@ -2202,6 +2204,8 @@ _e_comp_wl_surface_state_finish(E_Comp_Wl_Surface_State *state)
 
    if (state->buffer) wl_list_remove(&state->buffer_destroy_listener.link);
    state->buffer = NULL;
+
+   e_presentation_time_container_finish(&state->presentation_container);
 }
 
 static void
@@ -2449,6 +2453,10 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
                                            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 */
@@ -3334,6 +3342,8 @@ _e_comp_wl_client_cb_new(void *data EINA_UNUSED, E_Client *ec)
    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);
 
@@ -3419,6 +3429,8 @@ _e_comp_wl_client_cb_del(void *data EINA_UNUSED, E_Client *ec)
         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);
@@ -3991,6 +4003,7 @@ e_comp_wl_init(void)
    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);
@@ -4044,6 +4057,7 @@ e_comp_wl_shutdown(void)
    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();
index 882e177058289b02146cc0c273f7284d8246839c..d0e7cc2f1b085829f7925867dcad904803a7e891 100644 (file)
@@ -156,6 +156,8 @@ struct _E_Comp_Wl_Surface_State
    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
@@ -408,6 +410,7 @@ struct _E_Comp_Wl_Client_Data
    E_Comp_Wl_Surface_State pending;
 
    Eina_List *frames;
+   E_Presentation_Time_Container presentation_container;
 
    struct
      {
index 528ed2846386c48e1d419887c21d6cc8cd1e52c5..96812eaceca76abb78284d3045afa349bc4baf9d 100644 (file)
@@ -3,6 +3,7 @@
 # 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))
@@ -669,6 +670,8 @@ _e_hwc_window_free(E_Hwc_Window *hwc_window)
 
    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);
 
@@ -720,6 +723,7 @@ static E_Hwc_Window_Commit_Data *
 _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);
@@ -836,6 +840,8 @@ e_hwc_window_new(E_Hwc *hwc, E_Client *ec, E_Hwc_Window_State state)
 
    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);
@@ -1359,6 +1365,63 @@ e_hwc_window_commit_data_acquire(E_Hwc_Window *hwc_window)
    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)
 {
index 62954c5d28b39c072765de04d99e1ece02015782..61887daee4e59ae5f519f0ce3f8356a1b6ce191e 100644 (file)
@@ -141,6 +141,8 @@ struct _E_Hwc_Window
    Eina_Bool                      on_rendered_target;
 
    unsigned int                   restriction;
+
+   E_Presentation_Time_Container presentation_container;
 };
 
 struct _E_Hwc_Window_Target
@@ -225,5 +227,9 @@ EINTERN Eina_Bool               e_hwc_window_fps_get(E_Hwc_Window *hwc_window, d
 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
index a9bf5f655029c9efd8e93fc38f872263fd044fb8..a04fcabc8a679f0240c2f7f4c3ee96a106f785e5 100644 (file)
@@ -55,6 +55,7 @@
    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
 {
@@ -64,6 +65,11 @@ 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;
@@ -72,6 +78,9 @@ 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);
@@ -196,6 +205,75 @@ _e_hwc_windows_aligned_width_get(tbm_surface_h tsurface)
    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)
@@ -203,9 +281,17 @@ _e_hwc_windows_commit_data_release(E_Hwc *hwc, int sequence,
    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);
 
@@ -235,6 +321,8 @@ _e_hwc_windows_commit_data_acquire(E_Hwc *hwc)
           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);
 
@@ -278,6 +366,8 @@ _e_hwc_windows_offscreen_commit(E_Hwc *hwc)
    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)
@@ -293,11 +383,12 @@ _e_hwc_windows_offscreen_commit(E_Hwc *hwc)
 
         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);
      }
 }
@@ -333,6 +424,7 @@ _e_hwc_windows_target_window_buffer_skip(E_Hwc *hwc, Eina_Bool tdm_set)
    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;
 
@@ -350,6 +442,11 @@ _e_hwc_windows_target_window_buffer_skip(E_Hwc *hwc, Eina_Bool tdm_set)
    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);
@@ -468,7 +565,16 @@ _e_hwc_windows_target_buffer_fetch(E_Hwc *hwc, Eina_Bool tdm_set)
           {
              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);
@@ -884,6 +990,7 @@ _e_hwc_windows_target_window_render_flush_post_cb(void *data, Evas *e EINA_UNUSE
    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;
@@ -917,6 +1024,10 @@ _e_hwc_windows_target_window_render_flush_post_cb(void *data, Evas *e EINA_UNUSE
           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);
@@ -930,6 +1041,10 @@ _e_hwc_windows_target_window_render_flush_post_cb(void *data, Evas *e EINA_UNUSE
         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);
index 1e5d3e70be7e0622fad956b2647dae40a6ecc5e0..17a909833f2279f7554ace3af53faebfd57dc44b 100644 (file)
@@ -56,6 +56,7 @@
 #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"
index 1f88391b723ba06298b90004fdc593a19940319e..dea2a740980d6be0eb1c56a17128b1dfeaca4d64 100644 (file)
@@ -3225,6 +3225,14 @@ _e_info_client_proc_trace(int argc, char **argv)
                }
              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:
index 6c68385b6a633ebd3e2fa07b9fd33c89950e1979..f964a6b1c7c316a314ecbc3c2c50a881cbc60342 100644 (file)
@@ -4472,6 +4472,7 @@ e_info_server_cb_hwc_trace_message(const Eldbus_Service_Interface *iface EINA_UN
    return reply;
 }
 
+
 static Eldbus_Message *
 e_info_server_cb_serial_trace_message(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
 {
@@ -4490,6 +4491,24 @@ e_info_server_cb_serial_trace_message(const Eldbus_Service_Interface *iface EINA
    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)
 {
@@ -6286,6 +6305,7 @@ static const Eldbus_Method methods[] = {
    { "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},
index b3c726ad2ba2548981c778dfb0e7718854aba032..b6e307f349ad6549a6a2435e3e81b193fcabb1a4 100644 (file)
@@ -235,7 +235,9 @@ typedef enum
    "\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                                                                   */
index 316fc9076b6a2e0d2970923d443bcccd67c70d51..b5679cfe619ba600c8d3f5a720e16e1a2c996f69 100644 (file)
@@ -1097,9 +1097,13 @@ e_pixmap_buffer_clear(E_Pixmap *cp, Eina_Bool only_free)
 
    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);
diff --git a/src/bin/e_presentation_time.c b/src/bin/e_presentation_time.c
new file mode 100644 (file)
index 0000000..e719032
--- /dev/null
@@ -0,0 +1,440 @@
+#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");
+}
diff --git a/src/bin/e_presentation_time.h b/src/bin/e_presentation_time.h
new file mode 100644 (file)
index 0000000..8cf0cde
--- /dev/null
@@ -0,0 +1,52 @@
+#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