--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2020 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Contact: SooChan Lim <sc1.lim@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+**************************************************************************/
+
+#include "tc-wayland-extension.h"
+#include "mockcompositor.h"
+#include "mockclient.h"
+#include "tizen-hwc-server-protocol.h"
+#include "tizen-hwc-client-protocol.h"
+
+class TizenHwcTest : public ::testing::Test
+{
+public:
+ void SetUp(void) override {
+ setenv("XDG_RUNTIME_DIR", "/run", 1);
+ }
+
+ void TearDown(void) override {
+ unsetenv("XDG_RUNTIME_DIR");
+ }
+};
+
+class MockTizenHwcCompositor : public MockCompositor
+{
+public:
+ MockTizenHwcCompositor() {}
+ MockTizenHwcCompositor(const struct wl_interface *interface, int version, wl_global_bind_func_t bind)
+ : MockCompositor(interface, version, this, bind)
+ {}
+ ~MockTizenHwcCompositor()
+ {}
+
+ void CreateGlobalRes(const struct wl_interface *interface, int version, wl_global_bind_func_t bind);
+private:
+};
+
+class MockTizenHwcClient : public MockClient
+{
+public:
+ MockTizenHwcClient()
+ {}
+ MockTizenHwcClient(const struct wl_registry_listener *listener)
+ : MockClient(listener, this), hwc_commit_done(false)
+ {}
+ ~MockTizenHwcClient()
+ {}
+
+ void SetGlobalResWlCompositor(struct wl_compositor *global_res) {
+ compositor_res = global_res;
+ }
+
+ struct wl_compositor *GetGlobalResWlCompositor() {
+ return compositor_res;
+ }
+
+ void SetGlobalResTizenHwc(struct tizen_hwc *global_res) {
+ tizen_hwc = global_res;
+ }
+
+ struct tizen_hwc * GetGlobalResTizenHwc() {
+ return tizen_hwc;
+ }
+
+ void SetHwcCommitDone() {
+ hwc_commit_done = true;
+ }
+
+ bool CheckHwcCommitDone() {
+ return hwc_commit_done;
+ }
+
+private:
+ struct tizen_hwc *tizen_hwc;
+ struct wl_compositor *compositor_res;
+ bool hwc_commit_done;
+};
+
+static void
+compositor_tizen_hwc_cb_commit_feedback(struct wl_client *client,
+ struct wl_resource *tizen_hwc_resource,
+ struct wl_resource *surface_resource,
+ uint32_t id,
+ uint32_t serial)
+{
+ struct wl_resource *hwc_commit_feedback_resource;
+
+ // create frame callback
+ if (!(hwc_commit_feedback_resource= wl_resource_create(client, &tizen_hwc_commit_feedback_interface, 1, id))) {
+ wl_resource_post_no_memory(hwc_commit_feedback_resource);
+ return;
+ }
+
+ wl_resource_set_implementation(hwc_commit_feedback_resource, NULL, NULL, NULL);
+
+ // send committed.
+ tizen_hwc_commit_feedback_send_committed(hwc_commit_feedback_resource, serial);
+ wl_resource_destroy(hwc_commit_feedback_resource);
+}
+
+static void
+compositor_tizen_hwc_cb_destroy(struct wl_client *client, struct wl_resource *tizen_hwc_resource)
+{
+ std::cout << __func__ << "\n";
+ wl_resource_destroy(tizen_hwc_resource);
+}
+
+static const struct tizen_hwc_interface compositor_tizen_hwc_implementation = {
+ .destroy = compositor_tizen_hwc_cb_destroy,
+ .commit_feedback = compositor_tizen_hwc_cb_commit_feedback
+};
+
+static void
+compositor_tizen_hwc_handle_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ MockTizenHwcCompositor *c = static_cast<MockTizenHwcCompositor *>(data);
+ struct wl_resource *tizen_hwc_resource;
+
+ tizen_hwc_resource = wl_resource_create(client, &tizen_hwc_interface, version, id);
+ if (!tizen_hwc_resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(tizen_hwc_resource, &compositor_tizen_hwc_implementation, c, NULL);
+}
+
+static void
+client_registry_cb_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
+{
+ MockTizenHwcClient *client = static_cast<MockTizenHwcClient *>(data);
+ struct tizen_hwc *tizen_hwc;
+ struct wl_compositor *compositor_res;
+
+ if (!strcmp(interface, "wl_compositor")) {
+ compositor_res = (struct wl_compositor *)wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+ if (compositor_res == nullptr) {
+ std::cout << "fail to bind compositor_res\n";
+ return;
+ }
+ client->SetGlobalResWlCompositor(compositor_res);
+ } else if (!strcmp(interface, "tizen_hwc")) {
+ tizen_hwc = (struct tizen_hwc *)wl_registry_bind(registry, name, &tizen_hwc_interface, 1);
+ if (tizen_hwc == nullptr) {
+ std::cout << "fail to bind tizen_hwc\n";
+ return;
+ }
+ client->SetGlobalResTizenHwc(tizen_hwc);
+ }
+}
+
+static void
+client_registry_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
+{
+ MockTizenHwcClient *client = static_cast<MockTizenHwcClient *>(data);
+
+ tizen_hwc_destroy(client->GetGlobalResTizenHwc());
+ wl_compositor_destroy(client->GetGlobalResWlCompositor());
+}
+
+static const struct wl_registry_listener registry_listener = {
+ .global = client_registry_cb_global,
+ .global_remove = client_registry_cb_global_remove
+};
+
+static void
+client_tizen_hwc_commit_feedback_cb_committed (void *data,
+ struct tizen_hwc_commit_feedback *hwc_commit_feedback,
+ uint32_t serial)
+{
+ MockTizenHwcClient *client = static_cast<MockTizenHwcClient *>(data);
+
+ // get the hwc_commit done noti from compositor
+ client->SetHwcCommitDone();
+
+ tizen_hwc_commit_feedback_destroy(hwc_commit_feedback);
+}
+
+static void
+client_tizen_hwc_commit_feedback_cb_discarded (void *data,
+ struct tizen_hwc_commit_feedback *hwc_commit_feedback,
+ uint32_t serial)
+{
+ MockTizenHwcClient *client = static_cast<MockTizenHwcClient *>(data);
+
+ // get the hwc_commit done noti from compositor
+ client->SetHwcCommitDone();
+
+ tizen_hwc_commit_feedback_destroy(hwc_commit_feedback);
+}
+
+static const struct tizen_hwc_commit_feedback_listener hwc_commit_feedback_cb_listener = {
+ .committed = client_tizen_hwc_commit_feedback_cb_committed,
+ .discarded = client_tizen_hwc_commit_feedback_cb_discarded
+};
+
+TEST_F(TizenHwcTest, TizenHwcCommit)
+{
+ MockTizenHwcCompositor compositor(&tizen_hwc_interface, 1, compositor_tizen_hwc_handle_bind);
+ MockTizenHwcClient client(®istry_listener);
+
+ struct wl_surface *surface_res = wl_compositor_create_surface(client.GetGlobalResWlCompositor());
+
+ struct tizen_hwc *tizen_hwc = client.GetGlobalResTizenHwc();
+ struct tizen_hwc_commit_feedback *hwc_commit_feedback = tizen_hwc_commit_feedback(tizen_hwc, surface_res, 1);
+ tizen_hwc_commit_feedback_add_listener(hwc_commit_feedback,
+ &hwc_commit_feedback_cb_listener,
+ &client);
+ client.RoundTrip();
+ EXPECT_TRUE(client.CheckHwcCommitDone());
+
+ wl_surface_destroy(surface_res);
+}