subsurface: Add cached states 40/294240/1
authorSeunghun Lee <shiin.lee@samsung.com>
Wed, 22 Feb 2023 00:52:38 +0000 (09:52 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Thu, 15 Jun 2023 00:44:35 +0000 (09:44 +0900)
This makes subsurface work with cached states depending on the sync
mode.

Change-Id: I186de52c6c4bc20329e61e7ec2a85185dedfd6c8

src/compositor/compositor_private.h
src/compositor/subsurface.c
src/compositor/surface.c

index 1860be3..d8cf53b 100644 (file)
@@ -7,7 +7,6 @@
 #include <wayland-server.h>
 
 #include "libds/log.h"
-#include "libds/util/defs.h"
 #include "libds/util/box.h"
 #include "libds/util/addon.h"
 #include "libds/types/ds_surface.h"
@@ -42,6 +41,9 @@ struct ds_subsurface
         struct wl_listener parent_destroy;
     } listener;
 
+    struct ds_surface_state cached;
+    bool has_cache;
+
     bool synchronized;
     bool reordered;
     bool mapped;
@@ -55,6 +57,16 @@ void subcompositor_finish(struct ds_subcompositor *subcomp);
 struct ds_surface *
 create_surface(struct wl_client *client, uint32_t version, uint32_t id);
 
+void surface_state_move(struct ds_surface_state *state,
+        struct ds_surface_state *next);
+
+void surface_commit_state(struct ds_surface *surface,
+        struct ds_surface_state *next);
+
+void surface_state_init(struct ds_surface_state *state);
+
+void surface_state_finish(struct ds_surface_state *state);
+
 struct ds_surface *
 ds_surface_get_root_surface(struct ds_surface *surface);
 
@@ -69,4 +81,9 @@ subsurface_from_ds_surface(struct ds_surface *surface);
 struct ds_surface *
 subsurface_get_parent(struct ds_subsurface *subsurface);
 
+void subsurface_commit(struct ds_subsurface *subsurface);
+
+void subsurface_parent_commit(struct ds_subsurface *subsurface,
+        bool synchronized);
+
 #endif
index 719bb4c..d21a2a4 100644 (file)
@@ -14,6 +14,8 @@ static void subsurface_link_parent(struct ds_subsurface *subsurface,
 static void subsurface_unlink_parent(struct ds_subsurface *subsurface);
 static struct ds_subsurface *subsurface_find_sibling(struct ds_subsurface *subsurface,
         struct ds_surface *surface);
+static bool subsurface_is_synchronized(struct ds_subsurface *subsurface);
+static void subsurface_synchronized_commit(struct ds_subsurface *subsurface);
 
 struct ds_subsurface *
 create_subsurface(struct wl_resource *subcomp_resource,
@@ -70,6 +72,47 @@ ds_surface_is_subsurface(struct ds_surface *surface)
     return ds_surface_get_role(surface) == &subsurface_role;
 }
 
+void
+subsurface_commit(struct ds_subsurface *subsurface)
+{
+    struct ds_surface *surface = subsurface->surface;
+    struct ds_subsurface *child;
+
+    if (subsurface_is_synchronized(subsurface)) {
+        surface_state_move(&subsurface->cached, &surface->pending);
+        subsurface->has_cache = true;
+    }
+    else {
+        if (subsurface->has_cache) {
+            surface_state_move(&subsurface->cached, &surface->pending);
+            surface_commit_state(surface, &subsurface->cached);
+            subsurface->has_cache = false;
+        }
+        else {
+            surface_commit_state(surface, &surface->pending);
+        }
+
+        wl_list_for_each(child, &surface->current.subsurfaces_below, current.link)
+            subsurface_parent_commit(child, false);
+        wl_list_for_each(child, &surface->current.subsurfaces_above, current.link)
+            subsurface_parent_commit(child, false);
+    }
+}
+
+void
+subsurface_parent_commit(struct ds_subsurface *subsurface, bool synchronized)
+{
+    if (subsurface->current.x != subsurface->pending.x ||
+            subsurface->current.y != subsurface->pending.y) {
+        subsurface->current.x = subsurface->pending.x;
+        subsurface->current.y = subsurface->pending.y;
+    }
+
+    if (synchronized || subsurface->synchronized) {
+        subsurface_synchronized_commit(subsurface);
+    }
+}
+
 WL_EXPORT struct ds_subsurface *
 ds_subsurface_from_resource(struct wl_resource *resource)
 {
@@ -212,7 +255,8 @@ subsurface_handle_set_desync(struct wl_client *client,
     if (subsurface->synchronized) {
         subsurface->synchronized = false;
 
-        // TODO: flush
+        if (!subsurface_is_synchronized(subsurface))
+            subsurface_synchronized_commit(subsurface);
     }
 }
 
@@ -237,6 +281,7 @@ subsurface_destroy(struct ds_subsurface *subsurface)
     if (subsurface->surface)
         subsurface_unlink_surface(subsurface);
 
+    surface_state_finish(&subsurface->cached);
     wl_resource_set_user_data(subsurface->resource, NULL);
 
     free(subsurface);
@@ -336,3 +381,37 @@ subsurface_find_sibling(struct ds_subsurface *subsurface, struct ds_surface *sur
 
     return NULL;
 }
+
+static bool
+subsurface_is_synchronized(struct ds_subsurface *subsurface)
+{
+    struct ds_subsurface *iter = subsurface;
+
+    do {
+        if (iter->synchronized)
+            return true;
+
+        if (!iter->parent)
+            break;
+    } while ((iter = subsurface_from_ds_surface(iter->parent)));
+
+    return false;
+}
+
+static void
+subsurface_synchronized_commit(struct ds_subsurface *subsurface)
+{
+    struct ds_surface *surface = subsurface->surface;
+    struct ds_subsurface *child;
+
+    if (subsurface->has_cache) {
+        surface_state_move(&subsurface->cached, &surface->pending);
+        surface_commit_state(surface, &subsurface->cached);
+        subsurface->has_cache = false;
+    }
+
+    wl_list_for_each(child, &surface->current.subsurfaces_below, current.link)
+        subsurface_parent_commit(child, true);
+    wl_list_for_each(child, &surface->current.subsurfaces_above, current.link)
+        subsurface_parent_commit(child, true);
+}
index 9e58548..7ab9b29 100644 (file)
@@ -8,15 +8,12 @@
 static const struct wl_surface_interface surface_impl;
 
 static void surface_handle_resource_destroy(struct wl_resource *resource);
-static void surface_state_init(struct ds_surface_state *state);
-static void surface_state_finish(struct ds_surface_state *state);
-static void surface_state_move(struct ds_surface_state *state,
-        struct ds_surface_state *next);
 static void surface_finalize_pending(struct ds_surface *surface);
-static void surface_commit_state(struct ds_surface *surface,
-        struct ds_surface_state *next);
 static bool surface_for_each(struct ds_surface *surface, int x, int y,
         ds_surface_for_each_func_t iterator, void *data);
+static void surface_update_damage(pixman_region32_t *buffer_damage,
+        struct ds_surface_state *current, struct ds_surface_state *pending);
+static void surface_update_buffer(struct ds_surface *surface);
 
 WL_EXPORT void
 ds_surface_add_destroy_listener(struct ds_surface *surface,
@@ -303,6 +300,147 @@ ds_surface_get_wl_resource(struct ds_surface *surface)
     return surface->resource;
 }
 
+void
+surface_state_move(struct ds_surface_state *state, struct ds_surface_state *next)
+{
+    state->width = next->width;
+    state->height = next->height;
+    state->buffer_width = next->buffer_width;
+    state->buffer_height = next->buffer_height;
+
+    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_SCALE))
+        state->scale = next->scale;
+
+    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_TRANSFORM))
+        state->transform = next->transform;
+
+    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_BUFFER)) {
+        state->dx = next->dx;
+        state->dy = next->dy;
+        next->dx = next->dy = 0;
+
+        if (state->buffer) {
+            ds_buffer_unlock(state->buffer);
+            state->buffer = NULL;
+        }
+
+        if (next->buffer) {
+            state->buffer = ds_buffer_lock(next->buffer);
+            ds_buffer_unlock(next->buffer);
+            next->buffer = NULL;
+        }
+    }
+    else {
+        state->dx = state->dy = 0;
+    }
+
+    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_SURFACE_DAMAGE)) {
+        pixman_region32_copy(&state->surface_damage, &next->surface_damage);
+        pixman_region32_clear(&next->surface_damage);
+    }
+    else
+        pixman_region32_clear(&state->surface_damage);
+
+    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_BUFFER_DAMAGE)) {
+        pixman_region32_copy(&state->buffer_damage, &next->buffer_damage);
+        pixman_region32_clear(&next->buffer_damage);
+    }
+    else
+        pixman_region32_clear(&state->buffer_damage);
+
+    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_OPAQUE_REGION))
+        pixman_region32_copy(&state->opaque, &next->opaque);
+
+    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_INPUT_REGION))
+        pixman_region32_copy(&state->input, &next->input);
+
+    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_VIEWPORT))
+        memcpy(&state->viewport, &next->viewport, sizeof(state->viewport));
+
+    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_FRAME_CALLBACK_LIST)) {
+        wl_list_insert_list(&state->frame_callback_list,
+                &next->frame_callback_list);
+        wl_list_init(&next->frame_callback_list);
+    }
+
+    // FIXME
+    // state->committed |= next->committed; ??
+    state->committed = next->committed;
+    next->committed = 0;
+}
+
+void
+surface_commit_state(struct ds_surface *surface, struct ds_surface_state *next)
+{
+    struct ds_subsurface *subsurface;
+
+    surface_finalize_pending(surface);
+
+    surface->sx += next->dx;
+    surface->sy += next->dy;
+    surface_update_damage(&surface->buffer_damage, &surface->current, next);
+
+    surface_state_move(&surface->current, next);
+
+    // FIXME no need?
+    if (DS_FLAG_IS_SET(surface->current.committed, DS_SURFACE_STATE_BUFFER))
+        surface_update_buffer(surface);
+
+
+    wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_above,
+            pending.link) {
+        wl_list_remove(&subsurface->current.link);
+        wl_list_insert(&surface->current.subsurfaces_above,
+                &subsurface->current.link);
+    }
+    wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_below,
+            pending.link) {
+        wl_list_remove(&subsurface->current.link);
+        wl_list_insert(&surface->current.subsurfaces_below,
+                &subsurface->current.link);
+    }
+
+    if (surface->role && surface->role->commit)
+        surface->role->commit(surface);
+
+    wl_signal_emit(&surface->events.commit, surface);
+}
+
+void
+surface_state_init(struct ds_surface_state *state)
+{
+    state->scale = 1;
+    state->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+
+    wl_list_init(&state->subsurfaces_above);
+    wl_list_init(&state->subsurfaces_below);
+
+    wl_list_init(&state->frame_callback_list);
+
+    pixman_region32_init(&state->surface_damage);
+    pixman_region32_init(&state->buffer_damage);
+    pixman_region32_init(&state->opaque);
+    pixman_region32_init_rect(&state->input,
+            INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX);
+}
+
+void
+surface_state_finish(struct ds_surface_state *state)
+{
+    struct wl_resource *resource, *tmp;
+
+    if (state->buffer)
+        ds_buffer_unlock(state->buffer);
+
+    wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list)
+        wl_resource_destroy(resource);
+
+    pixman_region32_fini(&state->surface_damage);
+    pixman_region32_fini(&state->buffer_damage);
+    pixman_region32_fini(&state->opaque);
+    pixman_region32_fini(&state->input);
+}
+
 static void
 surface_handle_destroy(struct wl_client *client, struct wl_resource *resource)
 {
@@ -442,18 +580,24 @@ static void
 surface_handle_commit(struct wl_client *client, struct wl_resource *resource)
 {
     struct ds_surface *surface;
+    struct ds_subsurface *subsurface, *child;
 
     surface = wl_resource_get_user_data(resource);
 
     ds_dbg("ds_surface(%p) commit", surface);
 
-    // TODO handle subsurface
-
-    surface_finalize_pending(surface);
+    if (ds_surface_is_subsurface(surface)) {
+        subsurface = subsurface_from_ds_surface(surface);
+        subsurface_commit(subsurface);
+        return;
+    }
 
     surface_commit_state(surface, &surface->pending);
 
-    // TODO handle subsurfaces of a given surface
+    wl_list_for_each(child, &surface->current.subsurfaces_below, current.link)
+        subsurface_parent_commit(child, false);
+    wl_list_for_each(child, &surface->current.subsurfaces_above, current.link)
+        subsurface_parent_commit(child, false);
 }
 
 static void
@@ -564,110 +708,6 @@ surface_handle_resource_destroy(struct wl_resource *resource)
 }
 
 static void
-surface_state_init(struct ds_surface_state *state)
-{
-    state->scale = 1;
-    state->transform = WL_OUTPUT_TRANSFORM_NORMAL;
-
-    wl_list_init(&state->subsurfaces_above);
-    wl_list_init(&state->subsurfaces_below);
-
-    wl_list_init(&state->frame_callback_list);
-
-    pixman_region32_init(&state->surface_damage);
-    pixman_region32_init(&state->buffer_damage);
-    pixman_region32_init(&state->opaque);
-    pixman_region32_init_rect(&state->input,
-            INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX);
-}
-
-static void
-surface_state_finish(struct ds_surface_state *state)
-{
-    struct wl_resource *resource, *tmp;
-
-    if (state->buffer)
-        ds_buffer_unlock(state->buffer);
-
-    wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list)
-        wl_resource_destroy(resource);
-
-    pixman_region32_fini(&state->surface_damage);
-    pixman_region32_fini(&state->buffer_damage);
-    pixman_region32_fini(&state->opaque);
-    pixman_region32_fini(&state->input);
-}
-
-static void
-surface_state_move(struct ds_surface_state *state, struct ds_surface_state *next)
-{
-    state->width = next->width;
-    state->height = next->height;
-    state->buffer_width = next->buffer_width;
-    state->buffer_height = next->buffer_height;
-
-    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_SCALE))
-        state->scale = next->scale;
-
-    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_TRANSFORM))
-        state->transform = next->transform;
-
-    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_BUFFER)) {
-        state->dx = next->dx;
-        state->dy = next->dy;
-        next->dx = next->dy = 0;
-
-        if (state->buffer) {
-            ds_buffer_unlock(state->buffer);
-            state->buffer = NULL;
-        }
-
-        if (next->buffer) {
-            state->buffer = ds_buffer_lock(next->buffer);
-            ds_buffer_unlock(next->buffer);
-            next->buffer = NULL;
-        }
-    }
-    else {
-        state->dx = state->dy = 0;
-    }
-
-    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_SURFACE_DAMAGE)) {
-        pixman_region32_copy(&state->surface_damage, &next->surface_damage);
-        pixman_region32_clear(&next->surface_damage);
-    }
-    else
-        pixman_region32_clear(&state->surface_damage);
-
-    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_BUFFER_DAMAGE)) {
-        pixman_region32_copy(&state->buffer_damage, &next->buffer_damage);
-        pixman_region32_clear(&next->buffer_damage);
-    }
-    else
-        pixman_region32_clear(&state->buffer_damage);
-
-    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_OPAQUE_REGION))
-        pixman_region32_copy(&state->opaque, &next->opaque);
-
-    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_INPUT_REGION))
-        pixman_region32_copy(&state->input, &next->input);
-
-    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_VIEWPORT))
-        memcpy(&state->viewport, &next->viewport, sizeof(state->viewport));
-
-    if (DS_FLAG_IS_SET(next->committed, DS_SURFACE_STATE_FRAME_CALLBACK_LIST)) {
-        wl_list_insert_list(&state->frame_callback_list,
-                &next->frame_callback_list);
-        wl_list_init(&next->frame_callback_list);
-    }
-
-    // FIXME 
-    // state->committed |= next->committed; ??
-    state->committed = next->committed;
-    next->committed = 0;
-}
-
-static void
 surface_state_viewport_src_size(struct ds_surface_state *state,
         int *out_width, int *out_height)
 {
@@ -826,25 +866,6 @@ surface_update_buffer(struct ds_surface *surface)
     }
 }
 
-static void
-surface_commit_state(struct ds_surface *surface, struct ds_surface_state *next)
-{
-    surface->sx += next->dx;
-    surface->sy += next->dy;
-    surface_update_damage(&surface->buffer_damage, &surface->current, next);
-
-    surface_state_move(&surface->current, next);
-
-    // FIXME no need?
-    if (DS_FLAG_IS_SET(surface->current.committed, DS_SURFACE_STATE_BUFFER))
-        surface_update_buffer(surface);
-
-    if (surface->role && surface->role->commit)
-        surface->role->commit(surface);
-
-    wl_signal_emit(&surface->events.commit, surface);
-}
-
 static bool
 surface_for_each(struct ds_surface *surface, int x, int y,
         ds_surface_for_each_func_t iterator, void *data)