viewport: do cache changes according to sub-surface sync mode. 90/242190/7
authorSeunghun Lee <shiin.lee@samsung.com>
Tue, 18 Aug 2020 14:10:38 +0000 (23:10 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Tue, 1 Sep 2020 01:17:20 +0000 (01:17 +0000)
Now that sub-surface issues SUBSURFACE_COMMIT_TO_CACHE event,
viewport can cache changes requested by client.
The cached state will be applied to current state on the next commit.

Change-Id: Id521b1cd61af4c5c5ba94a13db4e8f04828d1458

src/bin/e_comp_wl_viewport.c

index b01ae81..c2d110f 100644 (file)
@@ -31,29 +31,13 @@ typedef enum
    DESTINATION_TYPE_MODE,
 } E_Viewport_Destination_Type;
 
-typedef struct _E_Viewport
+typedef struct _E_Viewport_State
 {
-   struct wl_resource *resource;
-
-   E_Client *ec;
-   E_Client *epc;
-   Ecore_Window window;
-
-   Ecore_Event_Handler *topmost_rotate_hdl;
-
-   struct wl_listener surface_destroy_listener;
-   struct wl_listener surface_apply_viewport_listener;
-
-   Eina_Bool changed;
-
-   unsigned int transform;
-
    Eina_Rectangle source;
-   Eina_Rectangle cropped_source;
 
-   E_Viewport_Destination_Type type;
    struct
      {
+        E_Viewport_Destination_Type type;
         Eina_Rectangle rect;
 
         struct
@@ -63,8 +47,6 @@ typedef struct _E_Viewport
 
         struct
           {
-             struct wl_resource *resource;
-
              enum tizen_destination_mode_type type;
 
              double ratio_h;
@@ -83,16 +65,39 @@ typedef struct _E_Viewport
           } mode;
      } destination;
 
-   Eina_Bool query_parent_size;
-   Eina_Rectangle parent_size;
+   unsigned int transform;
 
    Eina_Bool follow_parent_transform;
+   Eina_Bool changed;
+} E_Viewport_State;
+
+typedef struct _E_Viewport
+{
+   struct wl_resource *resource;
+   struct wl_resource *dst_mode_res;
+
+   E_Client *ec;
+   E_Client *epc;
+   Ecore_Window window;
+
+   Ecore_Event_Handler *topmost_rotate_hdl;
+
+   struct wl_listener surface_destroy_listener;
+   struct wl_listener surface_apply_viewport_listener;
+
+   Eina_Rectangle cropped_source;
+
+   E_Viewport_State pending, cached, current;
+
+   Eina_Bool query_parent_size;
+   Eina_Rectangle parent_size;
 
    E_Client_Hook *client_hook_del;
    E_Client_Hook *client_hook_move;
    E_Client_Hook *client_hook_resize;
 
    E_Comp_Wl_Hook *subsurf_hook_create;
+   E_Comp_Wl_Hook *subsurf_hook_commit_to_cache;
 } E_Viewport;
 
 static E_Viewport* _e_comp_wl_viewport_get_viewport(struct wl_resource *resource);
@@ -142,14 +147,15 @@ _destroy_viewport(E_Viewport *viewport)
    e_client_hook_del(viewport->client_hook_resize);
 
    e_comp_wl_hook_del(viewport->subsurf_hook_create);
+   e_comp_wl_hook_del(viewport->subsurf_hook_commit_to_cache);
 
    wl_list_remove(&viewport->surface_destroy_listener.link);
    wl_list_remove(&viewport->surface_apply_viewport_listener.link);
 
    wl_resource_set_user_data(viewport->resource, NULL);
 
-   if (viewport->destination.mode.resource)
-     wl_resource_set_user_data(viewport->destination.mode.resource, NULL);
+   if (viewport->dst_mode_res)
+     wl_resource_set_user_data(viewport->dst_mode_res, NULL);
 
    if (ec->comp_data && ec->comp_data->scaler.viewport)
      {
@@ -179,6 +185,26 @@ _subsurface_cb_create(void *data, E_Client *ec)
 }
 
 static void
+_e_comp_wl_viewport_hook_subsurface_commit_to_cache(void *data, E_Client *ec)
+{
+   E_Viewport *viewport;
+
+   viewport = data;
+   if (viewport->ec != ec) return;
+
+   /* copy pending state to cached state */
+   viewport->cached = viewport->pending;
+
+   /* clear pending.changed */
+   viewport->pending.changed = EINA_FALSE;
+
+   /* Whether pending state was changed or not, the cached.changed should
+    * be set as true. The reason behind this is to decide to get which one,
+    * between cached state and pending state in following commit. */
+   viewport->cached.changed = EINA_TRUE;
+}
+
+static void
 _client_cb_del(void *data, E_Client *ec)
 {
    E_Viewport *viewport = data;
@@ -254,7 +280,7 @@ _e_comp_wl_viewport_set_changed(E_Viewport *viewport)
 
    if (!viewport) return;
 
-   viewport->changed = EINA_TRUE;
+   viewport->current.changed = EINA_TRUE;
 
    ec = viewport->ec;
    EINA_LIST_FOREACH(ec->comp_data->sub.list, l, subc)
@@ -283,12 +309,12 @@ _e_comp_wl_destination_mode_destroy(struct wl_resource *resource)
 
    if (!viewport) return;
 
-   if (viewport->type == DESTINATION_TYPE_MODE)
-     viewport->type = DESTINATION_TYPE_NONE;
+   if (viewport->current.destination.type == DESTINATION_TYPE_MODE)
+     viewport->current.destination.type = DESTINATION_TYPE_NONE;
 
    _e_comp_wl_viewport_set_changed(viewport);
 
-   viewport->destination.mode.resource = NULL;
+   viewport->dst_mode_res = NULL;
 
    PIN("destination.mode destroy");
 }
@@ -308,13 +334,13 @@ _e_comp_wl_destination_mode_cb_follow_parent_transform(struct wl_client *client
 
    if (!viewport) return;
 
-   if (viewport->follow_parent_transform)
+   if (viewport->pending.follow_parent_transform)
      return;
 
    PIN("follow_parent_transform");
 
-   viewport->follow_parent_transform = EINA_TRUE;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.follow_parent_transform = EINA_TRUE;
+   viewport->pending.changed = EINA_TRUE;
 }
 
 static void
@@ -325,13 +351,13 @@ _e_comp_wl_destination_mode_cb_unfollow_parent_transform(struct wl_client *clien
 
    if (!viewport) return;
 
-   if (!viewport->follow_parent_transform)
+   if (!viewport->pending.follow_parent_transform)
      return;
 
    PIN("unfollow_parent_transform");
 
-   viewport->follow_parent_transform = EINA_FALSE;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.follow_parent_transform = EINA_FALSE;
+   viewport->pending.changed = EINA_TRUE;
 }
 
 static void
@@ -349,18 +375,18 @@ _e_comp_wl_destination_mode_cb_set(struct wl_client *client,
         return;
      }
 
-   if (viewport->type == DESTINATION_TYPE_MODE && viewport->destination.mode.type == type)
+   if (viewport->pending.destination.type == DESTINATION_TYPE_MODE && viewport->pending.destination.mode.type == type)
      {
         PWR("skipped: set twice");
         return;
      }
 
-   viewport->type = DESTINATION_TYPE_MODE;
+   viewport->pending.destination.type = DESTINATION_TYPE_MODE;
+   viewport->pending.changed = EINA_TRUE;
 
    PIN("type(%d)", type);
 
-   viewport->destination.mode.type = type;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.destination.mode.type = type;
 }
 
 static void
@@ -380,8 +406,8 @@ _e_comp_wl_destination_mode_cb_set_ratio(struct wl_client *client,
    if (ratio_h == -1.0)
      {
         PDB("reset destinatino ratio");
-        viewport->destination.mode.ratio_h = ratio_h;
-        _e_comp_wl_viewport_set_changed(viewport);
+        viewport->pending.destination.mode.ratio_h = ratio_h;
+        viewport->pending.changed = EINA_TRUE;
         return;
      }
 
@@ -391,15 +417,15 @@ _e_comp_wl_destination_mode_cb_set_ratio(struct wl_client *client,
         return;
      }
 
-   if (viewport->destination.mode.ratio_h == ratio_h &&
-       viewport->destination.mode.ratio_v == ratio_v)
+   if (viewport->pending.destination.mode.ratio_h == ratio_h &&
+       viewport->pending.destination.mode.ratio_v == ratio_v)
      return;
 
    PIN("ratio_h(%.2f) ratio_v(%.2f)", ratio_h, ratio_v);
 
-   viewport->destination.mode.ratio_h = ratio_h;
-   viewport->destination.mode.ratio_v = ratio_v;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.destination.mode.ratio_h = ratio_h;
+   viewport->pending.destination.mode.ratio_v = ratio_v;
+   viewport->pending.changed = EINA_TRUE;
 }
 
 static void
@@ -419,8 +445,8 @@ _e_comp_wl_destination_mode_cb_set_scale(struct wl_client *client,
    if (scale_h == -1.0)
      {
         PDB("reset destinatino scale");
-        viewport->destination.mode.scale_h = scale_h;
-        _e_comp_wl_viewport_set_changed(viewport);
+        viewport->pending.destination.mode.scale_h = scale_h;
+        viewport->pending.changed = EINA_TRUE;
         return;
      }
 
@@ -430,15 +456,15 @@ _e_comp_wl_destination_mode_cb_set_scale(struct wl_client *client,
         return;
      }
 
-   if (viewport->destination.mode.scale_h == scale_h &&
-       viewport->destination.mode.scale_v == scale_v)
+   if (viewport->pending.destination.mode.scale_h == scale_h &&
+       viewport->pending.destination.mode.scale_v == scale_v)
      return;
 
    PIN("scale_h(%.2f) scale_v(%.2f)", scale_h, scale_v);
 
-   viewport->destination.mode.scale_h = scale_h;
-   viewport->destination.mode.scale_v = scale_v;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.destination.mode.scale_h = scale_h;
+   viewport->pending.destination.mode.scale_v = scale_v;
+   viewport->pending.changed = EINA_TRUE;
 }
 
 static void
@@ -458,8 +484,8 @@ _e_comp_wl_destination_mode_cb_set_align(struct wl_client *client,
    if (align_h == -1.0)
      {
         PDB("reset destinatino align");
-        viewport->destination.mode.align_h = align_h;
-        _e_comp_wl_viewport_set_changed(viewport);
+        viewport->pending.destination.mode.align_h = align_h;
+        viewport->pending.changed = EINA_TRUE;
         return;
      }
 
@@ -473,15 +499,15 @@ _e_comp_wl_destination_mode_cb_set_align(struct wl_client *client,
    else if (align_v > 1.0)
      align_v = 1.0;
 
-   if (viewport->destination.mode.align_h == align_h &&
-       viewport->destination.mode.align_v == align_v)
+   if (viewport->pending.destination.mode.align_h == align_h &&
+       viewport->pending.destination.mode.align_v == align_v)
      return;
 
    PIN("align_h(%.2f) align_v(%.2f)", align_h, align_v);
 
-   viewport->destination.mode.align_h = align_h;
-   viewport->destination.mode.align_v = align_v;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.destination.mode.align_h = align_h;
+   viewport->pending.destination.mode.align_v = align_v;
+   viewport->pending.changed = EINA_TRUE;
 }
 
 static void
@@ -496,19 +522,19 @@ _e_comp_wl_destination_mode_cb_set_offset(struct wl_client *client,
 
    if (!viewport) return;
 
-   if (viewport->destination.mode.offset_x == x &&
-       viewport->destination.mode.offset_y == y &&
-       viewport->destination.mode.offset_w == w &&
-       viewport->destination.mode.offset_h == h)
+   if (viewport->pending.destination.mode.offset_x == x &&
+       viewport->pending.destination.mode.offset_y == y &&
+       viewport->pending.destination.mode.offset_w == w &&
+       viewport->pending.destination.mode.offset_h == h)
      return;
 
    PIN("offset_x(%d) offset_y(%d) offset_w(%d) offset_h(%d)", x, y, w, h);
 
-   viewport->destination.mode.offset_x = x;
-   viewport->destination.mode.offset_y = y;
-   viewport->destination.mode.offset_w = w;
-   viewport->destination.mode.offset_h = h;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.destination.mode.offset_x = x;
+   viewport->pending.destination.mode.offset_y = y;
+   viewport->pending.destination.mode.offset_w = w;
+   viewport->pending.destination.mode.offset_h = h;
+   viewport->pending.changed = EINA_TRUE;
 }
 
 static const struct tizen_destination_mode_interface _e_comp_wl_destination_mode_interface =
@@ -578,13 +604,13 @@ _e_comp_wl_viewport_cb_set_transform(struct wl_client *client EINA_UNUSED,
 
    _e_comp_wl_viewport_parent_check(viewport);
 
-   if (viewport->transform == transform)
+   if (viewport->pending.transform == transform)
      return;
 
    PIN("transform(%d)", transform);
 
-   viewport->transform = transform;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.transform = transform;
+   viewport->pending.changed = EINA_TRUE;
 }
 
 static void
@@ -601,18 +627,17 @@ _e_comp_wl_viewport_cb_set_source(struct wl_client *client EINA_UNUSED,
 
    _e_comp_wl_viewport_parent_check(viewport);
 
-   if (viewport->source.x == x && viewport->source.y == y &&
-       viewport->source.w == width && viewport->source.h == height)
+   if (viewport->pending.source.x == x && viewport->pending.source.y == y &&
+       viewport->pending.source.w == width && viewport->pending.source.h == height)
      return;
 
-   viewport->source.x = x;
-   viewport->source.y = y;
-   viewport->source.w = width;
-   viewport->source.h = height;
-   viewport->cropped_source = viewport->source;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.source.x = x;
+   viewport->pending.source.y = y;
+   viewport->pending.source.w = width;
+   viewport->pending.source.h = height;
+   viewport->pending.changed = EINA_TRUE;
 
-   PIN("source(%d,%d %dx%d)", EINA_RECTANGLE_ARGS(&viewport->source));
+   PIN("source(%d,%d %dx%d)", EINA_RECTANGLE_ARGS(&viewport->pending.source));
 }
 
 static void
@@ -635,23 +660,23 @@ _e_comp_wl_viewport_cb_set_destination(struct wl_client *client EINA_UNUSED,
 
    _e_comp_wl_viewport_parent_check(viewport);
 
-   if (viewport->type == DESTINATION_TYPE_RECT &&
-       viewport->destination.rect.x == x && viewport->destination.rect.y == y &&
-       viewport->destination.rect.w == width && viewport->destination.rect.h == height)
+   if (viewport->pending.destination.type == DESTINATION_TYPE_RECT &&
+       viewport->pending.destination.rect.x == x && viewport->pending.destination.rect.y == y &&
+       viewport->pending.destination.rect.w == width && viewport->pending.destination.rect.h == height)
      {
         PWR("skipped: set twice");
         return;
      }
 
-   viewport->type = DESTINATION_TYPE_RECT;
+   viewport->pending.destination.type = DESTINATION_TYPE_RECT;
 
    PIN("destination.rect(%d,%d %dx%d)", x, y, width, height);
 
-   viewport->destination.rect.x = x;
-   viewport->destination.rect.y = y;
-   viewport->destination.rect.w = width;
-   viewport->destination.rect.h = height;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.destination.rect.x = x;
+   viewport->pending.destination.rect.y = y;
+   viewport->pending.destination.rect.w = width;
+   viewport->pending.destination.rect.h = height;
+   viewport->pending.changed = EINA_TRUE;
 }
 
 static void
@@ -667,7 +692,7 @@ _e_comp_wl_viewport_cb_set_destination_ratio(struct wl_client *client EINA_UNUSE
 
    if (!viewport) return;
 
-   if (viewport->type == DESTINATION_TYPE_MODE)
+   if (viewport->pending.destination.type == DESTINATION_TYPE_MODE)
      {
         PER("couldn't set viewport destination ratio. tizen_viewport@%d has the mode",
             wl_resource_get_id(resource));
@@ -687,23 +712,23 @@ _e_comp_wl_viewport_cb_set_destination_ratio(struct wl_client *client EINA_UNUSE
         return;
      }
 
-   if (viewport->type == DESTINATION_TYPE_RATIO &&
-       viewport->destination.ratio.x == ratio_x && viewport->destination.ratio.y == ratio_y &&
-       viewport->destination.ratio.w == ratio_w && viewport->destination.ratio.h == ratio_h)
+   if (viewport->pending.destination.type == DESTINATION_TYPE_RATIO &&
+       viewport->pending.destination.ratio.x == ratio_x && viewport->pending.destination.ratio.y == ratio_y &&
+       viewport->pending.destination.ratio.w == ratio_w && viewport->pending.destination.ratio.h == ratio_h)
      {
         PWR("skipped: set twice");
         return;
      }
 
-   viewport->type = DESTINATION_TYPE_RATIO;
+   viewport->pending.destination.type = DESTINATION_TYPE_RATIO;
 
    PIN("destination.ratio(%.2f,%.2f %.2fx%.2f)", ratio_x, ratio_y, ratio_w, ratio_h);
 
-   viewport->destination.ratio.x = ratio_x;
-   viewport->destination.ratio.y = ratio_y;
-   viewport->destination.ratio.w = ratio_w;
-   viewport->destination.ratio.h = ratio_h;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.destination.ratio.x = ratio_x;
+   viewport->pending.destination.ratio.y = ratio_y;
+   viewport->pending.destination.ratio.w = ratio_w;
+   viewport->pending.destination.ratio.h = ratio_h;
+   viewport->pending.changed = EINA_TRUE;
 }
 static void
 _e_comp_wl_viewport_cb_get_destination_mode(struct wl_client *client,
@@ -732,15 +757,16 @@ _e_comp_wl_viewport_cb_get_destination_mode(struct wl_client *client,
         return;
      }
 
-   memset(&viewport->destination.mode, 0, sizeof viewport->destination.mode);
+   memset(&viewport->pending.destination.mode, 0, sizeof viewport->pending.destination.mode);
 
    PIN("destination.mode created");
 
-   viewport->destination.mode.resource = res;
-   viewport->destination.mode.type = TIZEN_DESTINATION_MODE_TYPE_NONE;
-   viewport->destination.mode.ratio_h = -1.0;
-   viewport->destination.mode.scale_h = -1.0;
-   viewport->destination.mode.align_h = -1.0;
+   viewport->dst_mode_res = res;
+
+   viewport->pending.destination.mode.type = TIZEN_DESTINATION_MODE_TYPE_NONE;
+   viewport->pending.destination.mode.ratio_h = -1.0;
+   viewport->pending.destination.mode.scale_h = -1.0;
+   viewport->pending.destination.mode.align_h = -1.0;
 
    /* set resource implementation */
    wl_resource_set_implementation(res, &_e_comp_wl_destination_mode_interface,
@@ -799,13 +825,13 @@ _e_comp_wl_viewport_cb_follow_parent_transform(struct wl_client *client EINA_UNU
 
    _e_comp_wl_viewport_parent_check(viewport);
 
-   if (viewport->follow_parent_transform)
+   if (viewport->pending.follow_parent_transform)
      return;
 
    PIN("follow_parent_transform");
 
-   viewport->follow_parent_transform = EINA_TRUE;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.follow_parent_transform = EINA_TRUE;
+   viewport->pending.changed = EINA_TRUE;
 }
 
 static void
@@ -818,13 +844,13 @@ _e_comp_wl_viewport_cb_unfollow_parent_transform(struct wl_client *client EINA_U
 
    _e_comp_wl_viewport_parent_check(viewport);
 
-   if (!viewport->follow_parent_transform)
+   if (!viewport->pending.follow_parent_transform)
      return;
 
    PIN("unfollow_parent_transform");
 
-   viewport->follow_parent_transform = EINA_FALSE;
-   _e_comp_wl_viewport_set_changed(viewport);
+   viewport->pending.follow_parent_transform = EINA_FALSE;
+   viewport->pending.changed = EINA_TRUE;
 }
 
 static const struct tizen_viewport_interface _e_comp_wl_viewport_interface =
@@ -1019,10 +1045,10 @@ _destination_mode_calculate_destination(E_Viewport *viewport, Eina_Rectangle *pr
    int sw = 0, sh = 0, transform;
    double rh = -1.0, rv = -1.0;
 
-   if (viewport->source.w != -1)
+   if (viewport->current.source.w != -1)
      {
-        sw = viewport->source.w;
-        sh = viewport->source.h;
+        sw = viewport->current.source.w;
+        sh = viewport->current.source.h;
      }
    else
      e_comp_wl_video_buffer_size_get(ec, &sw, &sh);
@@ -1035,23 +1061,23 @@ _destination_mode_calculate_destination(E_Viewport *viewport, Eina_Rectangle *pr
    PDB("parent(%dx%d) src(%dx%d)", prect->w, prect->h, sw, sh);
 
    /* ratio -> type -> scale -> offset -> align */
-   if (viewport->destination.mode.ratio_h != -1.0)
+   if (viewport->current.destination.mode.ratio_h != -1.0)
      {
         if (transform % 2)
           {
-             rh = viewport->destination.mode.ratio_v;
-             rv = viewport->destination.mode.ratio_h;
+             rh = viewport->current.destination.mode.ratio_v;
+             rv = viewport->current.destination.mode.ratio_h;
           }
         else
           {
-             rh = viewport->destination.mode.ratio_h;
-             rv = viewport->destination.mode.ratio_v;
+             rh = viewport->current.destination.mode.ratio_h;
+             rv = viewport->current.destination.mode.ratio_v;
           }
      }
 
    PDB("%dx%d %dx%d %.2fx%.2f (%d,%d %dx%d)", prect->w, prect->h, sw, sh, rh, rv, EINA_RECTANGLE_ARGS(rect));
 
-   switch(viewport->destination.mode.type)
+   switch(viewport->current.destination.mode.type)
      {
       case TIZEN_DESTINATION_MODE_TYPE_LETTER_BOX:
          _destination_mode_calculate_letter_box(prect->w, prect->h, sw, sh, rh, rv, rect);
@@ -1076,11 +1102,11 @@ _destination_mode_calculate_destination(E_Viewport *viewport, Eina_Rectangle *pr
 
    PDB("(%d,%d %dx%d)", EINA_RECTANGLE_ARGS(rect));
 
-   if (viewport->destination.mode.scale_h != -1.0)
+   if (viewport->current.destination.mode.scale_h != -1.0)
      {
         int new_x, new_y, new_w, new_h;
-        double h = viewport->destination.mode.scale_h;
-        double v = viewport->destination.mode.scale_v;
+        double h = viewport->current.destination.mode.scale_h;
+        double v = viewport->current.destination.mode.scale_v;
 
         if (transform % 2)
           SWAP(h, v);
@@ -1097,11 +1123,11 @@ _destination_mode_calculate_destination(E_Viewport *viewport, Eina_Rectangle *pr
 
    PDB("(%d,%d %dx%d)", EINA_RECTANGLE_ARGS(rect));
 
-   if (viewport->destination.mode.align_h != -1.0)
+   if (viewport->current.destination.mode.align_h != -1.0)
      {
         E_Client *epc = viewport->epc;
-        double h = viewport->destination.mode.align_h;
-        double v = viewport->destination.mode.align_v;
+        double h = viewport->current.destination.mode.align_h;
+        double v = viewport->current.destination.mode.align_v;
         int dx, dy;
 
         if (epc)
@@ -1159,15 +1185,15 @@ _destination_mode_calculate_destination(E_Viewport *viewport, Eina_Rectangle *pr
 
    PDB("(%d,%d %dx%d)", EINA_RECTANGLE_ARGS(rect));
 
-   if (viewport->destination.mode.offset_x != 0 ||
-       viewport->destination.mode.offset_y != 0 ||
-       viewport->destination.mode.offset_w != 0 ||
-       viewport->destination.mode.offset_h != 0)
+   if (viewport->current.destination.mode.offset_x != 0 ||
+       viewport->current.destination.mode.offset_y != 0 ||
+       viewport->current.destination.mode.offset_w != 0 ||
+       viewport->current.destination.mode.offset_h != 0)
      {
-        int x = viewport->destination.mode.offset_x;
-        int y = viewport->destination.mode.offset_y;
-        int w = viewport->destination.mode.offset_w;
-        int h = viewport->destination.mode.offset_h;
+        int x = viewport->current.destination.mode.offset_x;
+        int y = viewport->current.destination.mode.offset_y;
+        int w = viewport->current.destination.mode.offset_w;
+        int h = viewport->current.destination.mode.offset_h;
 
         if (transform % 2)
           {
@@ -1189,24 +1215,24 @@ _destination_mode_calculate_destination(E_Viewport *viewport, Eina_Rectangle *pr
 static Eina_Bool
 _e_comp_wl_viewport_calculate_destination(E_Viewport *viewport, Eina_Rectangle *prect, Eina_Rectangle *rect)
 {
-   switch (viewport->type)
+   switch (viewport->current.destination.type)
      {
       case DESTINATION_TYPE_RECT:
-         rect->x = viewport->destination.rect.x;
-         rect->y = viewport->destination.rect.y;
-         rect->w = viewport->destination.rect.w;
-         rect->h = viewport->destination.rect.h;
+         rect->x = viewport->current.destination.rect.x;
+         rect->y = viewport->current.destination.rect.y;
+         rect->w = viewport->current.destination.rect.w;
+         rect->h = viewport->current.destination.rect.h;
          break;
       case DESTINATION_TYPE_RATIO:
-         rect->x = viewport->destination.ratio.x * prect->w;
-         rect->y = viewport->destination.ratio.y * prect->h;
-         rect->w = viewport->destination.ratio.w * prect->w;
-         rect->h = viewport->destination.ratio.h * prect->h;
+         rect->x = viewport->current.destination.ratio.x * prect->w;
+         rect->y = viewport->current.destination.ratio.y * prect->h;
+         rect->w = viewport->current.destination.ratio.w * prect->w;
+         rect->h = viewport->current.destination.ratio.h * prect->h;
          break;
       case DESTINATION_TYPE_MODE:
       case DESTINATION_TYPE_NONE:
       default:
-         PER("wrong destination type: %d", viewport->type);
+         PER("wrong destination type: %d", viewport->current.destination.mode.type);
          return EINA_FALSE;
      }
 
@@ -1249,7 +1275,7 @@ _e_comp_wl_viewport_crop_by_parent(E_Viewport *viewport, Eina_Rectangle *parent,
 
    if (crop.w == dst->w && crop.h == dst->h)
      {
-        if (viewport->source.w == -1)
+        if (viewport->current.source.w == -1)
           {
              e_comp_wl_video_buffer_size_get(viewport->ec, &bw, &bh);
 
@@ -1258,7 +1284,7 @@ _e_comp_wl_viewport_crop_by_parent(E_Viewport *viewport, Eina_Rectangle *parent,
              viewport->cropped_source.h = bh;
           }
         else
-          viewport->cropped_source = viewport->source;
+          viewport->cropped_source = viewport->current.source;
 
         PDB("src(%d,%d %dx%d)", EINA_RECTANGLE_ARGS(&viewport->cropped_source));
 
@@ -1290,14 +1316,14 @@ _e_comp_wl_viewport_crop_by_parent(E_Viewport *viewport, Eina_Rectangle *parent,
 
    e_comp_wl_video_buffer_size_get(viewport->ec, &bw, &bh);
 
-   if (viewport->source.w == -1)
+   if (viewport->current.source.w == -1)
      {
         viewport->cropped_source.x = viewport->cropped_source.y = 0;
         viewport->cropped_source.w = bw;
         viewport->cropped_source.h = bh;
      }
    else
-     viewport->cropped_source = viewport->source;
+     viewport->cropped_source = viewport->current.source;
 
    PDB("src(%d,%d %dx%d) ratio(%.2f,%.2f,%.2f,%.2f)",
        EINA_RECTANGLE_ARGS(&viewport->cropped_source), rx, ry, rw, rh);
@@ -1318,9 +1344,9 @@ _e_comp_wl_viewport_apply_transform(E_Viewport *viewport, int *rtransform)
    Eina_Bool changed = EINA_FALSE;
    unsigned int new_transform;
 
-   new_transform = viewport->transform;
+   new_transform = viewport->current.transform;
 
-   if (viewport->follow_parent_transform && viewport->epc)
+   if (viewport->current.follow_parent_transform && viewport->epc)
      {
         E_Client *epc = viewport->epc;
         unsigned int pwtran, ptran, pflip, ctran, cflip;
@@ -1340,8 +1366,8 @@ _e_comp_wl_viewport_apply_transform(E_Viewport *viewport, int *rtransform)
         ptran = ((pwtran & 0x3) + (ptransform & 0x3)) & 0x3;
         pflip = (ptransform & 0x4);
 
-        ctran = (viewport->transform & 0x3);
-        cflip = (viewport->transform & 0x4);
+        ctran = (viewport->current.transform & 0x3);
+        cflip = (viewport->current.transform & 0x4);
 
         new_transform = ((ptran + ctran) & 0x3) + ((pflip + cflip) & 0x4);
      }
@@ -1358,8 +1384,8 @@ _e_comp_wl_viewport_apply_transform(E_Viewport *viewport, int *rtransform)
 
    if (changed)
      PIN("apply transform: %d type(%d) follow(%d) changed(%d)",
-         vp->buffer.transform, viewport->type,
-         viewport->follow_parent_transform, changed);
+         vp->buffer.transform, viewport->current.destination.mode.type,
+         viewport->current.follow_parent_transform, changed);
 
    *rtransform = vp->buffer.transform;
 
@@ -1410,7 +1436,7 @@ _e_comp_wl_viewport_apply_destination(E_Viewport *viewport, Eina_Rectangle *rrec
         return EINA_FALSE;
      }
 
-   switch (viewport->type)
+   switch (viewport->current.destination.type)
      {
       case DESTINATION_TYPE_RECT:
       case DESTINATION_TYPE_RATIO:
@@ -1550,7 +1576,7 @@ e_comp_wl_viewport_apply(E_Client *ec)
         changed |= _e_comp_wl_viewport_apply_destination(viewport, &rrect);
         src_changed |= _e_comp_wl_viewport_apply_source(viewport);
 
-        viewport->changed = EINA_FALSE;
+        viewport->current.changed = EINA_FALSE;
 
         PDB("changed(%d) src_changed(%d)", changed, src_changed);
 
@@ -1594,7 +1620,7 @@ e_comp_wl_viewport_is_changed(E_Client *ec)
      return EINA_FALSE;
 
    viewport = _e_comp_wl_viewport_get_viewport(ec->comp_data->scaler.viewport);
-   if(viewport && viewport->changed)
+   if(viewport && viewport->current.changed)
      return EINA_TRUE;
 
    EINA_LIST_FOREACH(ec->comp_data->sub.list, l, subc)
@@ -1623,13 +1649,30 @@ _e_comp_wl_viewport_cb_apply_viewport(struct wl_listener *listener, void *data)
    E_Client *ec = viewport->ec;
    E_Client *topmost = _topmost_parent_get(ec);
    E_Comp_Wl_Buffer_Viewport *vp = &ec->comp_data->scaler.buffer_viewport;
+   Eina_Bool changed = EINA_FALSE;
 
    if (vp->changed)
+     changed = EINA_TRUE;
+
+   if (viewport->cached.changed)
+     {
+        viewport->current = viewport->cached;
+        viewport->cached.changed = EINA_FALSE;
+        changed = EINA_TRUE;
+     }
+   else if (viewport->pending.changed)
+     {
+        viewport->current = viewport->pending;
+        viewport->pending.changed = EINA_FALSE;
+        changed = EINA_TRUE;
+     }
+
+   if (changed)
      _e_comp_wl_viewport_set_changed(viewport);
 
    _e_comp_wl_viewport_parent_check(viewport);
 
-   if (!viewport->changed) return;
+   if (!viewport->current.changed) return;
    if (!ec->comp_data->buffer_ref.buffer) return;
    if (viewport->epc && !viewport->epc->comp_data->buffer_ref.buffer) return;
 
@@ -1717,12 +1760,14 @@ e_comp_wl_viewport_create(struct wl_resource *resource,
    viewport->client_hook_resize = e_client_hook_add(E_CLIENT_HOOK_RESIZE_UPDATE, _client_cb_resize, viewport);
 
    viewport->subsurf_hook_create = e_comp_wl_hook_add(E_COMP_WL_HOOK_SUBSURFACE_CREATE, _subsurface_cb_create, viewport);
+   viewport->subsurf_hook_commit_to_cache = e_comp_wl_hook_add(E_COMP_WL_HOOK_SUBSURFACE_COMMIT_TO_CACHE, _e_comp_wl_viewport_hook_subsurface_commit_to_cache, viewport);
 
    viewport->topmost_rotate_hdl =
       ecore_event_handler_add(E_EVENT_CLIENT_ROTATION_CHANGE_END,
                               _e_comp_wl_viewport_cb_topmost_rotate, viewport);
 
-   viewport->source.w = -1;
+   viewport->current.source.w = -1;
+   viewport->pending.source.w = -1;
    viewport->cropped_source.w = -1;
 
    viewport->surface_apply_viewport_listener.notify = _e_comp_wl_viewport_cb_apply_viewport;
@@ -1803,48 +1848,48 @@ _e_comp_wl_viewport_print(void *data, const char *log_path)
           }
         else
           fprintf(log_fl, "\n");
-        if (viewport->transform > 0)
+        if (viewport->current.transform > 0)
           fprintf(log_fl, "\t  transform: %d%s\n",
-                  (viewport->transform & 0x3) * 90 % 360,
-                  (viewport->transform & 0x4) ? "(flipped)" : "");
-        if (viewport->follow_parent_transform)
+                  (viewport->current.transform & 0x3) * 90 % 360,
+                  (viewport->current.transform & 0x4) ? "(flipped)" : "");
+        if (viewport->current.follow_parent_transform)
           fprintf(log_fl, "\t     follow: parent's transform\n");
-        if (viewport->source.w != -1)
+        if (viewport->current.source.w != -1)
           fprintf(log_fl, "\t     source: %dx%d+%d+%d\n",
-                  viewport->source.w, viewport->source.h,
-                  viewport->source.x, viewport->source.y);
-        fprintf(log_fl, "\t       type: %s\n", dest_type_str[viewport->type]);
-        if (viewport->type == DESTINATION_TYPE_RECT)
+                  viewport->current.source.w, viewport->current.source.h,
+                  viewport->current.source.x, viewport->current.source.y);
+        fprintf(log_fl, "\t       type: %s\n", dest_type_str[viewport->current.destination.type]);
+        if (viewport->current.destination.type == DESTINATION_TYPE_RECT)
           fprintf(log_fl, "\t  dest_rect: %dx%d+%d+%d\n",
-                  viewport->destination.rect.w, viewport->destination.rect.h,
-                  viewport->destination.rect.x, viewport->destination.rect.y);
-        else if (viewport->type == DESTINATION_TYPE_RATIO)
+                  viewport->current.destination.rect.w, viewport->current.destination.rect.h,
+                  viewport->current.destination.rect.x, viewport->current.destination.rect.y);
+        else if (viewport->current.destination.type == DESTINATION_TYPE_RATIO)
           fprintf(log_fl, "\t dest_ratio: %.2fx%.2f+%.2f+%.2f\n",
-                  viewport->destination.ratio.w, viewport->destination.ratio.h,
-                  viewport->destination.ratio.x, viewport->destination.ratio.y);
-        else if (viewport->type == DESTINATION_TYPE_MODE)
+                  viewport->current.destination.ratio.w, viewport->current.destination.ratio.h,
+                  viewport->current.destination.ratio.x, viewport->current.destination.ratio.y);
+        else if (viewport->current.destination.type == DESTINATION_TYPE_MODE)
           {
              fprintf(log_fl, "\t       mode: %s\n",
-                     mode_str[viewport->destination.mode.type]);
-             if (viewport->destination.mode.ratio_h != -1.0)
+                     mode_str[viewport->current.destination.mode.type]);
+             if (viewport->current.destination.mode.ratio_h != -1.0)
                fprintf(log_fl, "\t\t    ratio: H(%.2f) V(%.2f)\n",
-                       viewport->destination.mode.ratio_h,
-                       viewport->destination.mode.ratio_v);
-             if (viewport->destination.mode.scale_h != -1.0)
+                       viewport->current.destination.mode.ratio_h,
+                       viewport->current.destination.mode.ratio_v);
+             if (viewport->current.destination.mode.scale_h != -1.0)
                fprintf(log_fl, "\t\t    scale: H(%.2f) V(%.2f)\n",
-                       viewport->destination.mode.scale_h,
-                       viewport->destination.mode.scale_v);
-             if (viewport->destination.mode.align_h != -1.0)
+                       viewport->current.destination.mode.scale_h,
+                       viewport->current.destination.mode.scale_v);
+             if (viewport->current.destination.mode.align_h != -1.0)
                fprintf(log_fl, "\t\t    align: H(%.2f) V(%.2f)\n",
-                       viewport->destination.mode.align_h,
-                       viewport->destination.mode.align_v);
-             if (viewport->destination.mode.offset_w != 0 ||
-                 viewport->destination.mode.offset_h != 0 ||
-                 viewport->destination.mode.offset_x != 0 ||
-                 viewport->destination.mode.offset_y != 0)
+                       viewport->current.destination.mode.align_h,
+                       viewport->current.destination.mode.align_v);
+             if (viewport->current.destination.mode.offset_w != 0 ||
+                 viewport->current.destination.mode.offset_h != 0 ||
+                 viewport->current.destination.mode.offset_x != 0 ||
+                 viewport->current.destination.mode.offset_y != 0)
                fprintf(log_fl, "\t\t   offset: W(%d) H(%d) (%d) Y(%d)\n",
-                       viewport->destination.mode.offset_w, viewport->destination.mode.offset_h,
-                       viewport->destination.mode.offset_x, viewport->destination.mode.offset_y);
+                       viewport->current.destination.mode.offset_w, viewport->current.destination.mode.offset_h,
+                       viewport->current.destination.mode.offset_x, viewport->current.destination.mode.offset_y);
           }
 
         fprintf(log_fl, "\n");