Flesh out tdm backend 30/278130/1
authorSeunghun Lee <shiin.lee@samsung.com>
Thu, 24 Feb 2022 06:01:07 +0000 (15:01 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:58:05 +0000 (14:58 +0900)
Change-Id: Idf59ff423465f1f44102058ff017c12b5f54f042

include/libds/backend/tdm.h [new file with mode: 0644]
src/libds/backend/tdm/backend.c
src/libds/backend/tdm/output.c
src/libds/backend/tdm/tdm.h

diff --git a/include/libds/backend/tdm.h b/include/libds/backend/tdm.h
new file mode 100644 (file)
index 0000000..ec5f9cc
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef LIBDS_BACKEND_TDM_H
+#define LIBDS_BACKEND_TDM_H
+
+#include <libds/backend.h>
+
+struct ds_backend *
+ds_tdm_backend_create(struct wl_display *display);
+
+#endif
index 582fe62..2772f84 100644 (file)
@@ -27,7 +27,9 @@ ds_tdm_backend_create(struct wl_display *display)
 
     tdm->wl_display = display;
     tdm->clock = CLOCK_MONOTONIC;   // FIXME
+
     wl_list_init(&tdm->outputs);
+    wl_list_init(&tdm->buffers);
 
     tdm->tdm_display = tdm_display_init(&err);
     if (err != TDM_ERROR_NONE) {
@@ -74,6 +76,17 @@ tdm_backend_from_backend(struct ds_backend *backend)
 static void
 tdm_backend_destroy(struct ds_tdm_backend *tdm)
 {
+    struct ds_tdm_output *output, *tmp_output;
+    struct ds_tdm_buffer *buffer, *tmp_buffer;
+
+    wl_list_for_each_safe(output, tmp_output, &tdm->outputs, link) {
+        ds_output_destroy(&output->base);
+    }
+
+    wl_list_for_each_safe(buffer, tmp_buffer, &tdm->buffers, link) {
+        destroy_tdm_buffer(buffer);
+    }
+
     wl_list_remove(&tdm->display_destroy.link);
     wl_event_source_remove(tdm->tdm_event);
     close(tdm->fd);
index 74a0e29..08b56b5 100644 (file)
@@ -2,11 +2,14 @@
 #include <stdlib.h>
 
 #include "libds/log.h"
+#include "libds/allocator/tbm.h"
 #include "tdm.h"
+#include <tbm_surface.h>
 
 static const struct ds_output_interface tdm_output_iface;
 static bool tdm_output_init_modes(struct ds_tdm_output *output);
 static void tdm_output_destroy(struct ds_tdm_output *output);
+static void tdm_output_init_hwc(struct ds_tdm_output *output);
 
 struct ds_tdm_output *
 create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output)
@@ -22,8 +25,8 @@ create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output)
     ds_output_init(&output->base, &tdm->base, &tdm_output_iface,
             tdm->wl_display);
 
-    output->tdm = tdm;
-    output->tdm_output = tdm_output;
+    output->backend = tdm;
+    output->tdm.output = tdm_output;
 
     err = tdm_output_get_conn_status(tdm_output, &conn);
     if (err != TDM_ERROR_NONE) {
@@ -45,7 +48,10 @@ create_tdm_output(struct ds_tdm_backend *tdm, tdm_output *tdm_output)
         output->status = DS_TDM_OUTPUT_DISCONNECTED;
     }
 
-    ds_inf("TDM output(%p) created.", output);
+    if (tdm_output_get_hwc(output->tdm.output, NULL) != NULL)
+        tdm_output_init_hwc(output);
+
+    ds_inf("TDM output(%p) created: hwc(%p)", output, output->tdm.hwc);
 
     return output;
 
@@ -71,10 +77,148 @@ tdm_output_iface_destroy(struct ds_output *ds_output)
     tdm_output_destroy(output);
 }
 
+void
+destroy_tdm_buffer(struct ds_tdm_buffer *buffer)
+{
+    if (buffer == NULL)
+        return;
+
+    wl_list_remove(&buffer->buffer_destroy.link);
+    wl_list_remove(&buffer->link);
+    free(buffer);
+}
+
+static void
+buffer_handle_buffer_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_tdm_buffer *buffer;
+
+    buffer = wl_container_of(listener, buffer, buffer_destroy);
+    destroy_tdm_buffer(buffer);
+}
+
+static struct ds_tdm_buffer *
+create_tdm_buffer(struct ds_tdm_backend *backend, struct ds_buffer *ds_buffer)
+{
+    struct ds_tdm_buffer *buffer;
+    tbm_surface_h surface;
+
+    surface = ds_tbm_buffer_get_surface(ds_buffer);
+    if (!surface) {
+        ds_err("Could not get tbm_surface_h");
+        return NULL;
+    }
+
+    buffer = calloc(1, sizeof *buffer);
+    if (!buffer) {
+        return NULL;
+    }
+
+    buffer->surface = surface;
+    buffer->buffer = ds_buffer_lock(ds_buffer);
+    wl_list_insert(&backend->buffers, &buffer->link);
+
+    buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
+    ds_buffer_add_destroy_listener(ds_buffer, &buffer->buffer_destroy);
+
+    return buffer;
+}
+
+static struct ds_tdm_buffer *
+get_or_create_tdm_buffer(struct ds_tdm_backend *backend,
+        struct ds_buffer *ds_buffer)
+{
+    struct ds_tdm_buffer *buffer;
+
+    wl_list_for_each(buffer, &backend->buffers, link) {
+        if (buffer->buffer == ds_buffer && buffer->released) {
+            buffer->released = false;
+            ds_buffer_lock(buffer->buffer);
+            return buffer;
+        }
+    }
+
+    return create_tdm_buffer(backend, ds_buffer);
+}
+
+static void
+tdm_output_hwc_commit_handler(tdm_hwc *hwc, unsigned int sequence,
+        unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+{
+    struct ds_tdm_output *output;
+
+    output = user_data;
+
+    if (output->front_buffer) {
+        output->front_buffer->released = true;
+        ds_buffer_unlock(output->front_buffer->buffer);
+    }
+
+    output->front_buffer = output->back_buffer;
+    output->back_buffer = NULL;
+
+    wl_signal_emit(&output->base.events.frame, &output->base);
+}
+
 static bool
 tdm_output_iface_commit(struct ds_output *ds_output)
 {
-    // TODO
+    struct ds_tdm_output *output;
+    struct ds_tdm_buffer *buffer;
+    struct ds_buffer *ds_buffer;
+
+    output = tdm_output_from_output(ds_output);
+
+    ds_buffer = ds_output->pending.buffer;
+    buffer = get_or_create_tdm_buffer(output->backend, ds_buffer);
+    if (!buffer)
+        return false;
+
+    if (ds_output->pending.committed & DS_OUTPUT_STATE_BUFFER) {
+        tdm_region fb_damage;
+        tdm_error err;
+        uint32_t num_changes;
+
+        memset(&fb_damage, 0, sizeof(fb_damage));
+        err = tdm_hwc_set_client_target_buffer(output->tdm.hwc,
+                buffer->surface, fb_damage);
+        if (err != TDM_ERROR_NONE) {
+            ds_err("Could not set hwc client target buffer");
+            ds_buffer_unlock(buffer->buffer);
+            return false;
+        }
+
+        err = tdm_hwc_validate(output->tdm.hwc, NULL, 0, &num_changes);
+        if (err != TDM_ERROR_NONE) {
+            ds_err("Could not hwc validate");
+            ds_buffer_unlock(buffer->buffer);
+            return false;
+        }
+
+        err = tdm_hwc_accept_validation(output->tdm.hwc);
+        if (err != TDM_ERROR_NONE) {
+            ds_err("Could not hwc accept validation");
+            ds_buffer_unlock(buffer->buffer);
+            return false;
+        }
+
+        err = tdm_hwc_commit(output->tdm.hwc, 0, tdm_output_hwc_commit_handler, output);
+        if (err != TDM_ERROR_NONE) {
+            ds_err("Could not hwc commit");
+            ds_buffer_unlock(buffer->buffer);
+            return false;
+        }
+
+        if (output->back_buffer) {
+            output->back_buffer->released = true;
+            ds_buffer_unlock(output->back_buffer->buffer);
+        }
+
+        output->back_buffer = buffer;
+
+        ds_dbg("Swap Buffer!!!!!");
+    }
+
     return true;
 }
 
@@ -94,6 +238,12 @@ tdm_output_destroy(struct ds_tdm_output *output)
         free(mode);
     }
 
+    if (output->back_buffer)
+        ds_buffer_unlock(output->back_buffer->buffer);
+
+    if (output->front_buffer)
+        ds_buffer_unlock(output->front_buffer->buffer);
+
     free(output);
 }
 
@@ -105,7 +255,7 @@ tdm_output_init_modes(struct ds_tdm_output *output)
     tdm_error err;
     int num_modes, i;
 
-    err = tdm_output_get_available_modes(output->tdm_output, &tdm_modes,
+    err = tdm_output_get_available_modes(output->tdm.output, &tdm_modes,
             &num_modes);
     if (err != TDM_ERROR_NONE) {
         ds_err("Could not get available modes: output(%p)", output);
@@ -139,7 +289,27 @@ tdm_output_init_modes(struct ds_tdm_output *output)
             wl_list_insert(&output->base.modes, &mode->base.link);
         else
             wl_list_insert(output->base.modes.prev, &mode->base.link);
+
+        // FIXME
+        if (mode->base.preferred) {
+            err = tdm_output_set_mode(output->tdm.output, tdm_mode);
+            if (err != TDM_ERROR_NONE) {
+                ds_err("Could not set mode");
+            }
+        }
     }
 
     return true;
 }
+
+static void
+tdm_output_init_hwc(struct ds_tdm_output *output)
+{
+    tdm_error err;
+
+    output->tdm.hwc = tdm_output_get_hwc(output->tdm.output, &err);
+    if (err != TDM_ERROR_NONE || !output->tdm.hwc) {
+        ds_err("Could not get tdm_hwc: output(%p)", output);
+        return;
+    }
+}
index 3a8990b..2b1c1e4 100644 (file)
@@ -26,6 +26,7 @@ struct ds_tdm_backend
     struct wl_event_source *tdm_event;
 
     struct wl_list outputs; // ds_tdm_output.link
+    struct wl_list buffers; // ds_tdm_buffer.link
 
     struct wl_listener display_destroy;
 
@@ -37,17 +38,35 @@ struct ds_tdm_output
 {
     struct ds_output base;
 
-    struct ds_tdm_backend *tdm;
-    tdm_output *tdm_output;
+    struct ds_tdm_backend *backend;
+    struct ds_tdm_buffer *front_buffer, *back_buffer;
+
+    struct {
+        tdm_output *output;
+        tdm_hwc *hwc;
+    } tdm;
 
     struct wl_list link;
 
     enum ds_tdm_output_status status;
 };
 
+struct ds_tdm_buffer
+{
+    struct ds_buffer *buffer;
+    tbm_surface_h surface;
+    struct wl_list link; // ds_wl_backend.buffers
+    struct wl_listener buffer_destroy;
+
+    bool released;
+};
+
 struct ds_tdm_backend *tdm_backend_from_backend(struct ds_backend *backend);
 
 struct ds_tdm_output *create_tdm_output(struct ds_tdm_backend *tdm,
         tdm_output *tdm_output);
 
+void destroy_tdm_buffer(struct ds_tdm_buffer *buffer);
+
+
 #endif