From d89f28c7e44df10f3c70f5097acf44014601266e Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 24 Feb 2022 15:01:07 +0900 Subject: [PATCH] Flesh out tdm backend Change-Id: Idf59ff423465f1f44102058ff017c12b5f54f042 --- include/libds/backend/tdm.h | 9 ++ src/libds/backend/tdm/backend.c | 13 +++ src/libds/backend/tdm/output.c | 180 ++++++++++++++++++++++++++++++++++++++-- src/libds/backend/tdm/tdm.h | 23 ++++- 4 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 include/libds/backend/tdm.h diff --git a/include/libds/backend/tdm.h b/include/libds/backend/tdm.h new file mode 100644 index 0000000..ec5f9cc --- /dev/null +++ b/include/libds/backend/tdm.h @@ -0,0 +1,9 @@ +#ifndef LIBDS_BACKEND_TDM_H +#define LIBDS_BACKEND_TDM_H + +#include + +struct ds_backend * +ds_tdm_backend_create(struct wl_display *display); + +#endif diff --git a/src/libds/backend/tdm/backend.c b/src/libds/backend/tdm/backend.c index 582fe62..2772f84 100644 --- a/src/libds/backend/tdm/backend.c +++ b/src/libds/backend/tdm/backend.c @@ -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); diff --git a/src/libds/backend/tdm/output.c b/src/libds/backend/tdm/output.c index 74a0e29..08b56b5 100644 --- a/src/libds/backend/tdm/output.c +++ b/src/libds/backend/tdm/output.c @@ -2,11 +2,14 @@ #include #include "libds/log.h" +#include "libds/allocator/tbm.h" #include "tdm.h" +#include 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; + } +} diff --git a/src/libds/backend/tdm/tdm.h b/src/libds/backend/tdm/tdm.h index 3a8990b..2b1c1e4 100644 --- a/src/libds/backend/tdm/tdm.h +++ b/src/libds/backend/tdm/tdm.h @@ -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 -- 2.7.4