diff options
Diffstat (limited to 'waltham-transmitter/transmitter-plugin/output.c')
-rw-r--r-- | waltham-transmitter/transmitter-plugin/output.c | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/waltham-transmitter/transmitter-plugin/output.c b/waltham-transmitter/transmitter-plugin/output.c new file mode 100644 index 0000000..c379ce5 --- /dev/null +++ b/waltham-transmitter/transmitter-plugin/output.c @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2017 Advanced Driver Information Technology Joint Venture GmbH + * + * 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, sublicense, 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * 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 <stdlib.h> +#include <assert.h> +#include <string.h> + +#include "compositor.h" +#include "compositor-drm.h" +#include "plugin-registry.h" + +#include "plugin.h" +#include "transmitter_api.h" +#include "waltham-renderer.h" + +/** @file + * + * This is an implementation of a remote output. + * + * A remote output must not be accepted as an argument to: + * - wl_shell_surface.set_fullscreen + * - wl_shell_surface.set_maximized + * - zwp_fullscreen_shell_v1.present_surface + * - zwp_fullscreen_shell_v1.present_surface_for_mode + * - zwp_input_panel_surface_v1.set_toplevel + * - xdg_surface.set_fullscreen + * + * If a remote output is an argument to the above or similar requests, + * it should have the same effect as NULL if possible. + * + * @todo Should we instead accept the argument and have it start remoting + * automatically? That would be shell-specific. + * + * In ivi-shell's case, only zwp_input_panel_surface_v1.set_toplevel is + * reachable from keyboard.c. That just blindly uses whatever the first + * output happens to be, so there is no need to check for now. + * + * @todo Add weston_output_set_remote() which sets weston_output::is_remote + * to true and inits weston_output::link. This should be made mutually + * exclusive with weston_compositor_add_output(). + */ + +static struct waltham_renderer_interface *waltham_renderer; + +static char * +make_model(struct weston_transmitter_remote *remote, int name) +{ + char *str; + + if (asprintf(&str, "transmitter-%s:%s-%d", remote->addr, remote->port, name) < 0) + return NULL; + + return str; +} + +static int +make_mode_list(struct wl_list *list, + const struct weston_transmitter_output_info *info) +{ + struct weston_mode *mode; + + mode = zalloc(sizeof *mode); + if (!mode) + return -1; + + *mode = info->mode; + wl_list_insert(list->prev, &mode->link); + + return 0; +} + +static struct weston_mode * +get_current_mode(struct wl_list *mode_list) +{ + struct weston_mode *mode; + + wl_list_for_each(mode, mode_list, link) + if (mode->flags & WL_OUTPUT_MODE_CURRENT) + return mode; + + assert(0); + return NULL; +} + +static void +free_mode_list(struct wl_list *mode_list) +{ + struct weston_mode *mode; + + while (!wl_list_empty(mode_list)) { + mode = wl_container_of(mode_list->next, mode, link); + + wl_list_remove(&mode->link); + free(mode); + } +} + +void +transmitter_output_destroy(struct weston_transmitter_output *output) +{ + wl_list_remove(&output->link); + + free_mode_list(&output->base.mode_list); + free(output->base.serial_number); + free(output->base.model); + free(output->base.make); + + weston_output_destroy(&output->base); + free(output); +} + +static void +transmitter_output_destroy_(struct weston_output *base) +{ + struct weston_transmitter_output *output = wl_container_of(base, output, base); + + transmitter_output_destroy(output); +} + + +static void +transmitter_start_repaint_loop(struct weston_output *base) +{ + struct timespec ts; + struct weston_transmitter_output *output = wl_container_of(base, output, base); + + weston_compositor_read_presentation_clock(output->base.compositor, &ts); + weston_output_finish_frame(&output->base, &ts, 0); +} + +static int +transmitter_output_repaint(struct weston_output *base, + pixman_region32_t *damage) +{ + struct weston_transmitter_output* output = wl_container_of(base, output, base); + struct weston_transmitter_remote* remote = output->remote; + struct weston_transmitter* txr = remote->transmitter; + struct weston_transmitter_api* transmitter_api = + weston_get_transmitter_api(txr->compositor); + struct weston_transmitter_surface* txs; + struct weston_compositor *compositor = base->compositor; + struct weston_view *view; + bool found_output = false; + struct timespec ts; + + struct weston_drm_output_api *api = + weston_plugin_api_get(txr->compositor, WESTON_DRM_OUTPUT_API_NAME, sizeof(api)); + + /* + * Pick up weston_view in transmitter_output and check weston_view's surface + * If the surface hasn't been conbined to weston_transmitter_surface, + * then call push_to_remote. + * If the surface has already been combined, call gather_state. + */ + if (wl_list_empty(&compositor->view_list)) + goto out; + + if (remote->status == WESTON_TRANSMITTER_CONNECTION_DISCONNECTED) + goto out; + + wl_list_for_each_reverse(view, &compositor->view_list, link) { + bool found_surface = false; + if (view->output == &output->base) { + found_output = true; + wl_list_for_each(txs, &remote->surface_list, link) { + if (txs->surface == view->surface) { + found_surface = true; + if (!txs->wthp_surf) + transmitter_api->surface_push_to_remote + (view->surface, remote, NULL); + + output->renderer->dmafd = + api->get_dma_fd_from_view(&output->base, view); + if(!output->renderer->dmafd) { + weston_log("Failed to get dmafd\n"); + goto out; + } + + /* + * Updating the width x height + * from surface to gst-recorder + */ + output->renderer->surface_width + = view->surface->width; + output->renderer->surface_height + = view->surface->height; + + output->renderer->repaint_output(output); + output->renderer->dmafd = NULL; + transmitter_api->surface_gather_state(txs); + weston_buffer_reference(&view->surface->buffer_ref, NULL); + break; + } + } + if (!found_surface) + transmitter_api->surface_push_to_remote(view->surface, + remote, NULL); + } + } + if (!found_output) + goto out; + + weston_compositor_read_presentation_clock(output->base.compositor, &ts); + weston_output_finish_frame(&output->base, &ts, 0); + + return 0; + +out: + transmitter_start_repaint_loop(base); + + return 0; +} + +static void +transmitter_assign_planes(struct weston_output *base) { + /* + * This function prevents compositor releasing buffer early. + */ + struct weston_transmitter_output* output = wl_container_of(base, output, base); + struct weston_transmitter_remote* remote = output->remote; + struct weston_transmitter_surface* txs; + struct weston_compositor *compositor = base->compositor; + struct weston_view *view; + + wl_list_for_each_reverse(view, &compositor->view_list, link) { + if (view->output == &output->base) { + wl_list_for_each(txs, &remote->surface_list, link) { + if (txs->surface == view->surface) + view->surface->keep_buffer = true; + + } + } + } +} + +static void +transmitter_output_enable(struct weston_output *base) +{ + struct weston_transmitter_output *output = wl_container_of(base, output, base); + + output->base.assign_planes = transmitter_assign_planes; + output->base.set_backlight = NULL; + output->base.set_dpms = NULL; + output->base.switch_mode = NULL; +} + +int +transmitter_remote_create_output(struct weston_transmitter_remote *remote, + const struct weston_transmitter_output_info *info) +{ + struct weston_transmitter_output *output; + struct weston_transmitter *txr = remote->transmitter; + struct weston_output *def_output; + + output = zalloc(sizeof *output); + if (!output) + return -1; + + output->parent.draw_initial_frame = true; + + output->base.subpixel = info->subpixel; + + output->base.name = make_model(remote, 1); + output->base.make = strdup(WESTON_TRANSMITTER_OUTPUT_MAKE); + output->base.model = make_model(remote, 1); + output->base.serial_number = strdup("0"); + /* x and y is fake value */ + wl_list_init(&output->base.mode_list); + if (make_mode_list(&output->base.mode_list, info) < 0) + goto fail; + + output->base.current_mode = get_current_mode(&output->base.mode_list); + output->base.height = output->base.current_mode->height; + output->base.width = output->base.current_mode->width; + /* WL_OUTPUT_MODE_CURRENT already set */ + weston_output_init(&output->base, remote->transmitter->compositor); + + /* + * renderer_output_create skipped: + * no renderer awareness is needed for this output + */ + + /* + * weston_compositor_add_output() skipped: + * Most other code uses weston_compositor::output_list when traversing + * all outputs, we do not want any of that. + * Also weston_compositor::output_created_signal must not trigger + * for this output, since we must not involve input device management + * or color management or any kind of local management. + */ + output->base.enable = transmitter_output_enable; + output->base.start_repaint_loop = transmitter_start_repaint_loop; + output->base.repaint = transmitter_output_repaint; + output->base.destroy = transmitter_output_destroy_; + output->base.assign_planes = NULL; + output->base.set_dpms = NULL; + output->base.switch_mode = NULL; + output->base.gamma_size = 0; + output->base.set_gamma = NULL; + + output->base.native_mode = output->base.current_mode; + output->base.native_scale = output->base.current_scale; + output->base.scale = 1; + output->base.transform = WL_OUTPUT_TRANSFORM_NORMAL; + + output->remote = remote; + wl_list_insert(&remote->output_list, &output->link); + + /* Loading a waltham renderer library */ + waltham_renderer = weston_load_module("waltham-renderer.so","waltham_renderer_interface"); + + if (waltham_renderer->display_create(output) < 0) { + weston_log("Failed to create waltham renderer display \n"); + return -1; + } + + weston_output_enable(&output->base); + + return 0; + +fail: + free_mode_list(&output->base.mode_list); + free(output->base.serial_number); + free(output->base.model); + free(output->base.make); + free(output->base.name); + free(output); + + return -1; +} |