From 2d2ba4d16f5fcbaf9eb97f0905dbae4740076bf2 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Tue, 7 Jun 2022 13:31:32 +0900 Subject: [PATCH] example: add tinyds-tdm-dpms Change-Id: Ic63b2893120fc46865559a49e0dc34c376f3a1ca Signed-off-by: Junkyeong Kim --- packaging/libds.spec | 1 + src/examples/meson.build | 13 + src/examples/tinyds-tdm-dpms.c | 672 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 686 insertions(+) create mode 100644 src/examples/tinyds-tdm-dpms.c diff --git a/packaging/libds.spec b/packaging/libds.spec index ed21c53..aefff95 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -107,6 +107,7 @@ ninja -C builddir install %{_bindir}/ds-simple-tbm %{_bindir}/tinyds-tdm-libinput %{_bindir}/ds-simple-shm-shell +%{_bindir}/tinyds-tdm-dpms %files tizen-keyrouter %manifest %{name}.manifest diff --git a/src/examples/meson.build b/src/examples/meson.build index 5c5c437..aad893e 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -82,4 +82,17 @@ if get_option('tizen') install_dir: libds_bindir, install : true ) + executable('tinyds-tdm-dpms', + 'tinyds-tdm-dpms.c', + 'pixman-helper.c', + 'pixman-tbm-helper.c', + 'tinyds-tdm-renderer.c', + dependencies: [ + common_deps, + dependency('pixman-1', required: true), + dependency('threads', required: true), + ], + install_dir: libds_bindir, + install : true + ) endif diff --git a/src/examples/tinyds-tdm-dpms.c b/src/examples/tinyds-tdm-dpms.c new file mode 100644 index 0000000..dc32e8f --- /dev/null +++ b/src/examples/tinyds-tdm-dpms.c @@ -0,0 +1,672 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USE_TDM_BUFFER_QUEUE + +#ifdef USE_TDM_BUFFER_QUEUE +#include "pixman-tbm-helper.h" +#include "tinyds-tdm-renderer.h" +#else +#include +#endif + +#include "pixman-helper.h" + +#define TINYDS_UNUSED __attribute__((unused)) + +struct tinyds_output +{ + struct tinyds_server *server; + struct ds_output *ds_output; + struct ds_allocator *allocator; +#ifdef USE_TDM_BUFFER_QUEUE + struct tinyds_renderer renderer; + struct ds_tdm_buffer_queue *buffer_queue; + struct wl_listener buffer_queue_acquirable; +#else + struct ds_swapchain *swapchain; +#endif + struct ds_buffer *front_buffer; + + struct wl_listener output_destroy; + struct wl_listener output_frame; + + int width, height; + + bool drawable; + bool damaged; +}; + +struct tinyds_dpms +{ + struct ds_tizen_dpms *ds_dpms; + struct tinyds_server *server; + + struct wl_listener destroy; + struct wl_listener set_dpms; + struct wl_listener get_dpms; +}; + +struct tinyds_server +{ + struct ds_tbm_server *tbm_server; + + struct wl_display *display; + + struct ds_backend *backend; + struct ds_compositor *compositor; + struct ds_xdg_shell *xdg_shell; + + struct tinyds_output *output; + struct tinyds_dpms *dpms; + struct wl_event_source *stdin_source; + + struct wl_list views; + + struct wl_listener new_output; + struct wl_listener new_xdg_surface; +}; + +struct tinyds_view +{ + struct tinyds_server *server; + + struct tinyds_texture *texture; + struct ds_xdg_surface *xdg_surface; + + struct wl_listener xdg_surface_map; + struct wl_listener xdg_surface_unmap; + struct wl_listener xdg_surface_destroy; + struct wl_listener surface_commit; + struct wl_list link; // tinyds_server::views + + int x, y; + bool mapped; +}; + +struct tinyds_server tinyds; + +static bool init_server(struct tinyds_server *server, struct wl_display *display); +static int server_dispatch_stdin(int fd, uint32_t mask, void *data); +static void output_handle_destroy(struct wl_listener *listener, void *data); +static void output_handle_frame(struct wl_listener *listener, void *data); +static void draw_server_with_damage(struct tinyds_server *server); +static void draw_output(struct tinyds_output *output); +static void output_swap_buffer(struct tinyds_output *output, + struct ds_buffer *buffer); +static void view_send_frame_done(struct tinyds_view *view); +#ifdef USE_TDM_BUFFER_QUEUE +static void output_buffer_queue_init(struct tinyds_output *output); +static void output_renderer_init(struct tinyds_output *output); +static void output_draw_with_renderer(struct tinyds_output *output); +#else +static void output_swapchain_init(struct tinyds_output *output, + int width, int height, uint32_t format); +static void output_draw_with_swapchain(struct tinyds_output *output); +static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image); +#endif +static void dpms_handle_destroy(struct wl_listener *listener, void *data); +static void dpms_handle_set_dpms(struct wl_listener *listener, void *data); +static void dpms_handle_get_dpms(struct wl_listener *listener, void *data); + + +int +main(void) +{ + struct tinyds_server *server = &tinyds; + struct wl_display *display; + struct wl_event_loop *loop; + const char *socket; + bool res; + + ds_log_init(DS_INF, NULL); + + display = wl_display_create(); + assert(display); + + res = init_server(server, display); + assert(res); + + socket = wl_display_add_socket_auto(display); + assert(socket); + + ds_backend_start(server->backend); + + setenv("WAYLAND_DISPLAY", socket, true); + + ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket); + + loop = wl_display_get_event_loop(display); + server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO, + WL_EVENT_READABLE, server_dispatch_stdin, server); + + wl_display_run(display); + + wl_display_destroy_clients(display); + wl_display_destroy(display); + + return 0; +} + +static void +view_handle_xdg_surface_map(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, xdg_surface_map); + view->mapped = true; +} + +static void +view_handle_xdg_surface_unmap(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, xdg_surface_unmap); + view->mapped = false; +} + +static void +view_handle_xdg_surface_destroy(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + struct tinyds_server *server; + + view = wl_container_of(listener, view, xdg_surface_destroy); + server = view->server; + + wl_list_remove(&view->xdg_surface_destroy.link); + wl_list_remove(&view->xdg_surface_map.link); + wl_list_remove(&view->xdg_surface_unmap.link); + wl_list_remove(&view->surface_commit.link); + wl_list_remove(&view->link); + free(view); + + draw_server_with_damage(server); +} + +static void +view_handle_surface_commit(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_view *view; + + view = wl_container_of(listener, view, surface_commit); + draw_server_with_damage(view->server); +} + +static void +server_new_xdg_surface(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct tinyds_view *view; + struct ds_xdg_surface *xdg_surface; + + server = wl_container_of(listener, server, new_xdg_surface); + xdg_surface = data; + + ds_inf("New xdg_surface(%p)", (void *)xdg_surface); + + view = calloc(1, sizeof *view); + assert(view); + + view->server = server; + view->xdg_surface = xdg_surface; + + view->xdg_surface_map.notify = view_handle_xdg_surface_map; + ds_xdg_surface_add_map_listener(xdg_surface, + &view->xdg_surface_map); + + view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap; + ds_xdg_surface_add_unmap_listener(xdg_surface, + &view->xdg_surface_unmap); + + view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy; + ds_xdg_surface_add_destroy_listener(xdg_surface, + &view->xdg_surface_destroy); + + view->surface_commit.notify = view_handle_surface_commit; + ds_surface_add_commit_listener( + ds_xdg_surface_get_surface(xdg_surface), + &view->surface_commit); + + wl_list_insert(server->views.prev, &view->link); + + view->x = rand() % 1000; + view->y = rand() % 500; +} + +static void +backend_handle_new_output(struct wl_listener *listener, void *data) +{ + struct tinyds_server *server; + struct tinyds_output *output; + struct ds_output *ds_output; + const struct ds_output_mode *mode; + + server = wl_container_of(listener, server, new_output); + ds_output = data; + + ds_inf("New output(%p)", ds_output); + + if (server->output) + return; + + mode = ds_output_get_preferred_mode(ds_output); + ds_output_set_mode(ds_output, mode); + + output = calloc(1, sizeof *output); + if (!output) + return; + + output->server = server; + output->ds_output = ds_output; + output->width = mode->width; + output->height = mode->height; + output->drawable = true; + output->damaged = true; + +#ifdef USE_TDM_BUFFER_QUEUE + output_buffer_queue_init(output); + output_renderer_init(output); +#else + output_swapchain_init(output, mode->width, mode->height, + DRM_FORMAT_XRGB8888); +#endif + + output->output_destroy.notify = output_handle_destroy; + ds_output_add_destroy_listener(ds_output, &output->output_destroy); + + output->output_frame.notify = output_handle_frame; + ds_output_add_frame_listener(ds_output, &output->output_frame); + + server->output = output; + + draw_output(output); +} + +static bool +add_new_dpms(struct tinyds_server *server) +{ + struct tinyds_dpms *dpms; + + dpms = calloc(1, sizeof *dpms); + if (!dpms) + return false; + + dpms->ds_dpms = ds_tizen_dpms_create(server->display); + if (!dpms->ds_dpms) + return false; + + dpms->destroy.notify = dpms_handle_destroy; + ds_tizen_dpms_add_destroy_listener(dpms->ds_dpms, &dpms->destroy); + + dpms->set_dpms.notify = dpms_handle_set_dpms; + ds_tizen_dpms_add_set_dpms_listener(dpms->ds_dpms, &dpms->set_dpms); + + dpms->get_dpms.notify = dpms_handle_get_dpms; + ds_tizen_dpms_add_get_dpms_listener(dpms->ds_dpms, &dpms->get_dpms); + + server->dpms = dpms; + + ds_inf("Dpms (%p) added", dpms); + + return true; +} + +static bool +init_server(struct tinyds_server *server, struct wl_display *display) +{ + server->display = display; + + wl_list_init(&server->views); + + if (wl_display_init_shm(display) != 0) + return false; + + server->backend = ds_tdm_backend_create(display); + if (!server->backend) + return false; + + server->new_output.notify = backend_handle_new_output; + ds_backend_add_new_output_listener(server->backend, + &server->new_output); + + server->compositor = ds_compositor_create(display); + if (!server->compositor) { + ds_backend_destroy(server->backend); + return false; + } + + server->tbm_server = ds_tbm_server_create(display); + if (!server->tbm_server) { + ds_backend_destroy(server->backend); + return false; + } + + server->xdg_shell = ds_xdg_shell_create(display); + if (!server->xdg_shell) { + ds_backend_destroy(server->backend); + return false; + } + + server->new_xdg_surface.notify = server_new_xdg_surface; + ds_xdg_shell_add_new_surface_listener(server->xdg_shell, + &server->new_xdg_surface); + + if (!add_new_dpms(server)) { + ds_backend_destroy(server->backend); + return false; + } + + return true; +} + +static void +output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED) +{ + struct tinyds_output *output = + wl_container_of(listener, output, output_destroy); + + wl_list_remove(&output->output_destroy.link); + wl_list_remove(&output->output_frame.link); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer); + +#ifdef USE_TDM_BUFFER_QUEUE + fini_renderer(&output->renderer); +#else + if (output->swapchain) + ds_swapchain_destroy(output->swapchain); + + if (output->allocator) + ds_allocator_destroy(output->allocator); +#endif + + wl_display_terminate(output->server->display); + + output->server->output = NULL; + + free(output); +} + +static void +output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED) +{ + struct tinyds_output *output = + wl_container_of(listener, output, output_frame); + + output->drawable = true; + draw_output(output); +} + +static void +draw_server_with_damage(struct tinyds_server *server) +{ + server->output->damaged = true; + draw_output(server->output); +} + +#ifdef USE_TDM_BUFFER_QUEUE +static void +output_handle_buffer_queue_acquirable(struct wl_listener *listener, + void *data TINYDS_UNUSED) +{ + struct tinyds_output *output; + struct ds_buffer *buffer; + + output = wl_container_of(listener, output, buffer_queue_acquirable); + + buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue); + assert(buffer); + + output_swap_buffer(output, buffer); +} + +static void +output_buffer_queue_init(struct tinyds_output *output) +{ + struct ds_tdm_output *tdm_output; + + tdm_output = ds_tdm_output_from_output(output->ds_output); + assert(tdm_output); + + output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output); + assert(output->buffer_queue); + + output->buffer_queue_acquirable.notify = + output_handle_buffer_queue_acquirable; + ds_tdm_buffer_queue_add_acquirable_listener(output->buffer_queue, + &output->buffer_queue_acquirable); +} + +static void +output_renderer_init(struct tinyds_output *output) +{ + init_renderer(&output->renderer); + + renderer_set_surface_queue(&output->renderer, + ds_tdm_buffer_queue_get_native_queue(output->buffer_queue)); + + renderer_set_bg_color(&output->renderer, 80, 80, 80); +} + +static void +output_draw_with_renderer(struct tinyds_output *output) +{ + struct tinyds_view *view; + + ds_dbg(">> BEGIN UPDATE TEXTURES"); + + wl_list_for_each(view, &output->server->views, link) { + struct ds_buffer *ds_buffer; + struct ds_tbm_client_buffer *tbm_buffer; + tbm_surface_h surface; + + if (!view->mapped) + continue; + + ds_buffer = ds_surface_get_buffer( + ds_xdg_surface_get_surface(view->xdg_surface)); + assert(ds_buffer); + + tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer); + assert(tbm_buffer); + + surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer); + + renderer_add_texture(&output->renderer, surface, view->x, view->y); + + view_send_frame_done(view); + } + + ds_dbg("<< END UPDATE TEXTURES"); + + renderer_draw(&output->renderer); + +} +#else +static void +output_swapchain_init(struct tinyds_output *output, + int width, int height, uint32_t format); + +{ + output->allocator = ds_tbm_allocator_create(); + assert(output->allocator); + + output->swapchain = ds_swapchain_create(output->allocator, + width, height, format); + assert(output->swapchain); +} + +static void +output_draw_with_swapchain(struct tinyds_output *output) +{ + struct tinyds_view *view; + struct ds_buffer *output_buffer; + pixman_image_t *output_image; + + output_buffer = ds_swapchain_acquire(output->swapchain, NULL); + if (!output_buffer) + return; + + output_image = pixman_image_from_buffer(output_buffer, + DS_BUFFER_DATA_PTR_ACCESS_WRITE); + if (!output_image) { + ds_buffer_unlock(output_buffer); + return; + } + + pixman_image_fill_color(output_image, 80, 80, 80); + + wl_list_for_each(view, &output->server->views, link) { + if (!view->mapped) + continue; + draw_view(view, output_image); + } + pixman_image_unref(output_image); + + output_swap_buffer(output, output_buffer); +} + +static void +draw_view(struct tinyds_view *view, pixman_image_t *dst_image) +{ + struct ds_buffer *buffer; + pixman_image_t *src_image; + + buffer = ds_surface_get_buffer( + ds_xdg_surface_get_surface(view->xdg_surface)); + if (!buffer) + return; + + src_image = pixman_image_from_buffer(buffer, + DS_BUFFER_DATA_PTR_ACCESS_READ); + pixman_image_composite32(PIXMAN_OP_OVER, + src_image, + NULL, + dst_image, + 0, 0, 0, 0, + view->x, view->y, + pixman_image_get_width(src_image), + pixman_image_get_height(src_image)); + pixman_image_unref(src_image); + + view_send_frame_done(view); +} +#endif + +static void +draw_output(struct tinyds_output *output) +{ + + if (!output->drawable || !output->damaged) + return; + +#ifdef USE_TDM_BUFFER_QUEUE + output_draw_with_renderer(output); +#else + output_draw_with_swapchain(output); +#endif + + output->drawable = false; + output->damaged = false; +} + +static void +output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer) +{ + ds_output_attach_buffer(output->ds_output, buffer); + ds_output_commit(output->ds_output); + + if (output->front_buffer) + ds_buffer_unlock(output->front_buffer); + output->front_buffer = buffer; +} + +static void +view_send_frame_done(struct tinyds_view *view) +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface), + &now); +} + +static int +server_dispatch_stdin(int fd, uint32_t mask, void *data) +{ + struct tinyds_server *server = data; + + wl_display_terminate(server->display); + + return 1; +} + +static void +dpms_handle_destroy(struct wl_listener *listener, void *data) +{ + struct tinyds_dpms *dpms; + + dpms = wl_container_of(listener, dpms, destroy); + + ds_inf("Dpms(%p) destroyed", dpms); + + wl_list_remove(&dpms->destroy.link); + wl_list_remove(&dpms->set_dpms.link); + wl_list_remove(&dpms->get_dpms.link); + + free(dpms); +} + +static void +dpms_handle_set_dpms(struct wl_listener *listener, void *data) +{ + struct tinyds_dpms *dpms; + struct ds_tizen_dpms_event *event = data; + + dpms = wl_container_of(listener, dpms, set_dpms); + + ds_inf("Dpms(%p) set dpms : %d", dpms, event->mode); + + //To do + //set dpms mode to output + ds_tizen_dpms_send_set_result(dpms->ds_dpms, event->mode, + DS_TIZEN_DPMS_ERROR_NONE); +} + +static void +dpms_handle_get_dpms(struct wl_listener *listener, void *data) +{ + struct tinyds_dpms *dpms; + + dpms = wl_container_of(listener, dpms, get_dpms); + + ds_inf("Dpms(%p) get dpms", dpms); + + //To do + //get dpms mode from output + ds_tizen_dpms_send_get_result(dpms->ds_dpms, DS_TIZEN_DPMS_MODE_ON, + DS_TIZEN_DPMS_ERROR_NONE); +} \ No newline at end of file -- 2.7.4