From 3654c673f81e8a1c88e60b4d3f4aec9d3938c2e8 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 9 Jul 2019 00:50:30 +0200 Subject: [PATCH] backend-drm: separate out DRM virtual support Move DRM virtual support into a separate file. Use the remoting compile time option to disable DRM virtual support since this is the only user of DRM virtual support currently. This will make it easier to build the DRM backend without GBM support. Signed-off-by: Stefan Agner --- libweston/backend-drm/drm-internal.h | 25 ++ libweston/backend-drm/drm-virtual.c | 362 +++++++++++++++++++++++++++ libweston/backend-drm/drm.c | 337 +------------------------ libweston/backend-drm/meson.build | 5 + 4 files changed, 398 insertions(+), 331 deletions(-) create mode 100644 libweston/backend-drm/drm-virtual.c diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index dbd5ace4..d43f292c 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -692,3 +692,28 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data); bool drm_plane_is_available(struct drm_plane *plane, struct drm_output *output); + +void +drm_output_render(struct drm_output_state *state, pixman_region32_t *damage); + +int +parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format); + +extern struct gl_renderer_interface *gl_renderer; + +#ifdef BUILD_DRM_VIRTUAL +extern int +drm_backend_init_virtual_output_api(struct weston_compositor *compositor); +#else +inline static int +drm_backend_init_virtual_output_api(struct weston_compositor *compositor) +{ + return 0; +} +#endif + +int +drm_output_init_egl(struct drm_output *output, struct drm_backend *b); +void +drm_output_fini_egl(struct drm_output *output); + diff --git a/libweston/backend-drm/drm-virtual.c b/libweston/backend-drm/drm-virtual.c new file mode 100644 index 00000000..ebebbbd2 --- /dev/null +++ b/libweston/backend-drm/drm-virtual.c @@ -0,0 +1,362 @@ +/* + * Copyright © 2008-2011 Kristian Høgsberg + * Copyright © 2011 Intel Corporation + * Copyright © 2017, 2018 Collabora, Ltd. + * Copyright © 2017, 2018 General Electric Company + * Copyright (c) 2018 DisplayLink (UK) Ltd. + * + * 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 "config.h" + +#include +#include +#include +#include +#include + +#include "drm-internal.h" +#include "renderer-gl/gl-renderer.h" + +/** + * Create a drm_plane for virtual output + * + * Call drm_virtual_plane_destroy to clean up the plane. + * + * @param b DRM compositor backend + * @param output Output to create internal plane for + */ +static struct drm_plane * +drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output) +{ + struct drm_plane *plane; + + /* num of formats is one */ + plane = zalloc(sizeof(*plane) + sizeof(plane->formats[0])); + if (!plane) { + weston_log("%s: out of memory\n", __func__); + return NULL; + } + + plane->type = WDRM_PLANE_TYPE_PRIMARY; + plane->backend = b; + plane->state_cur = drm_plane_state_alloc(NULL, plane); + plane->state_cur->complete = true; + plane->formats[0].format = output->gbm_format; + plane->count_formats = 1; + if ((output->gbm_bo_flags & GBM_BO_USE_LINEAR) && b->fb_modifiers) { + uint64_t *modifiers = zalloc(sizeof *modifiers); + if (modifiers) { + *modifiers = DRM_FORMAT_MOD_LINEAR; + plane->formats[0].modifiers = modifiers; + plane->formats[0].count_modifiers = 1; + } + } + + weston_plane_init(&plane->base, b->compositor, 0, 0); + wl_list_insert(&b->plane_list, &plane->link); + + return plane; +} + +/** + * Destroy one DRM plane + * + * @param plane Plane to deallocate (will be freed) + */ +static void +drm_virtual_plane_destroy(struct drm_plane *plane) +{ + drm_plane_state_free(plane->state_cur, true); + weston_plane_release(&plane->base); + wl_list_remove(&plane->link); + if (plane->formats[0].modifiers) + free(plane->formats[0].modifiers); + free(plane); +} + +static int +drm_virtual_output_start_repaint_loop(struct weston_output *output_base) +{ + weston_output_finish_frame(output_base, NULL, + WP_PRESENTATION_FEEDBACK_INVALID); + + return 0; +} + +static int +drm_virtual_output_submit_frame(struct drm_output *output, + struct drm_fb *fb) +{ + struct drm_backend *b = to_drm_backend(output->base.compositor); + int fd, ret; + + assert(fb->num_planes == 1); + ret = drmPrimeHandleToFD(b->drm.fd, fb->handles[0], DRM_CLOEXEC, &fd); + if (ret) { + weston_log("drmPrimeHandleFD failed, errno=%d\n", errno); + return -1; + } + + drm_fb_ref(fb); + ret = output->virtual_submit_frame(&output->base, fd, fb->strides[0], + fb); + if (ret < 0) { + drm_fb_unref(fb); + close(fd); + } + return ret; +} + +static int +drm_virtual_output_repaint(struct weston_output *output_base, + pixman_region32_t *damage, + void *repaint_data) +{ + struct drm_pending_state *pending_state = repaint_data; + struct drm_output_state *state = NULL; + struct drm_output *output = to_drm_output(output_base); + struct drm_plane *scanout_plane = output->scanout_plane; + struct drm_plane_state *scanout_state; + + assert(output->virtual); + + if (output->disable_pending || output->destroy_pending) + goto err; + + /* Drop frame if there isn't free buffers */ + if (!gbm_surface_has_free_buffers(output->gbm_surface)) { + weston_log("%s: Drop frame!!\n", __func__); + return -1; + } + + assert(!output->state_last); + + /* If planes have been disabled in the core, we might not have + * hit assign_planes at all, so might not have valid output state + * here. */ + state = drm_pending_state_get_output(pending_state, output); + if (!state) + state = drm_output_state_duplicate(output->state_cur, + pending_state, + DRM_OUTPUT_STATE_CLEAR_PLANES); + + drm_output_render(state, damage); + scanout_state = drm_output_state_get_plane(state, scanout_plane); + if (!scanout_state || !scanout_state->fb) + goto err; + + if (drm_virtual_output_submit_frame(output, scanout_state->fb) < 0) + goto err; + + return 0; + +err: + drm_output_state_free(state); + return -1; +} + +static void +drm_virtual_output_deinit(struct weston_output *base) +{ + struct drm_output *output = to_drm_output(base); + + drm_output_fini_egl(output); + + drm_virtual_plane_destroy(output->scanout_plane); +} + +static void +drm_virtual_output_destroy(struct weston_output *base) +{ + struct drm_output *output = to_drm_output(base); + + assert(output->virtual); + + if (output->base.enabled) + drm_virtual_output_deinit(&output->base); + + weston_output_release(&output->base); + + drm_output_state_free(output->state_cur); + + free(output); +} + +static int +drm_virtual_output_enable(struct weston_output *output_base) +{ + struct drm_output *output = to_drm_output(output_base); + struct drm_backend *b = to_drm_backend(output_base->compositor); + + assert(output->virtual); + + if (b->use_pixman) { + weston_log("Not support pixman renderer on Virtual output\n"); + goto err; + } + + if (!output->virtual_submit_frame) { + weston_log("The virtual_submit_frame hook is not set\n"); + goto err; + } + + output->scanout_plane = drm_virtual_plane_create(b, output); + if (!output->scanout_plane) { + weston_log("Failed to find primary plane for output %s\n", + output->base.name); + return -1; + } + + if (drm_output_init_egl(output, b) < 0) { + weston_log("Failed to init output gl state\n"); + goto err; + } + + output->base.start_repaint_loop = drm_virtual_output_start_repaint_loop; + output->base.repaint = drm_virtual_output_repaint; + output->base.assign_planes = drm_assign_planes; + output->base.set_dpms = NULL; + output->base.switch_mode = NULL; + output->base.gamma_size = 0; + output->base.set_gamma = NULL; + + weston_compositor_stack_plane(b->compositor, + &output->scanout_plane->base, + &b->compositor->primary_plane); + + return 0; +err: + return -1; +} + +static int +drm_virtual_output_disable(struct weston_output *base) +{ + struct drm_output *output = to_drm_output(base); + + assert(output->virtual); + + if (output->base.enabled) + drm_virtual_output_deinit(&output->base); + + return 0; +} + +static struct weston_output * +drm_virtual_output_create(struct weston_compositor *c, char *name) +{ + struct drm_output *output; + + output = zalloc(sizeof *output); + if (!output) + return NULL; + + output->virtual = true; + output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING; + + weston_output_init(&output->base, c, name); + + output->base.enable = drm_virtual_output_enable; + output->base.destroy = drm_virtual_output_destroy; + output->base.disable = drm_virtual_output_disable; + output->base.attach_head = NULL; + + output->state_cur = drm_output_state_alloc(output, NULL); + + weston_compositor_add_pending_output(&output->base, c); + + return &output->base; +} + +static uint32_t +drm_virtual_output_set_gbm_format(struct weston_output *base, + const char *gbm_format) +{ + struct drm_output *output = to_drm_output(base); + struct drm_backend *b = to_drm_backend(base->compositor); + + if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1) + output->gbm_format = b->gbm_format; + + return output->gbm_format; +} + +static void +drm_virtual_output_set_submit_frame_cb(struct weston_output *output_base, + submit_frame_cb cb) +{ + struct drm_output *output = to_drm_output(output_base); + + output->virtual_submit_frame = cb; +} + +static int +drm_virtual_output_get_fence_fd(struct weston_output *output_base) +{ + return gl_renderer->create_fence_fd(output_base); +} + +static void +drm_virtual_output_buffer_released(struct drm_fb *fb) +{ + drm_fb_unref(fb); +} + +static void +drm_virtual_output_finish_frame(struct weston_output *output_base, + struct timespec *stamp, + uint32_t presented_flags) +{ + struct drm_output *output = to_drm_output(output_base); + struct drm_plane_state *ps; + + wl_list_for_each(ps, &output->state_cur->plane_list, link) + ps->complete = true; + + drm_output_state_free(output->state_last); + output->state_last = NULL; + + weston_output_finish_frame(&output->base, stamp, presented_flags); + + /* We can't call this from frame_notify, because the output's + * repaint needed flag is cleared just after that */ + if (output->recorder) + weston_output_schedule_repaint(&output->base); +} + +static const struct weston_drm_virtual_output_api virt_api = { + drm_virtual_output_create, + drm_virtual_output_set_gbm_format, + drm_virtual_output_set_submit_frame_cb, + drm_virtual_output_get_fence_fd, + drm_virtual_output_buffer_released, + drm_virtual_output_finish_frame +}; + +int drm_backend_init_virtual_output_api(struct weston_compositor *compositor) +{ + return weston_plugin_api_register(compositor, + WESTON_DRM_VIRTUAL_OUTPUT_API_NAME, + &virt_api, sizeof(virt_api)); +} diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index ac4088a9..d37837dc 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -69,7 +69,7 @@ #include "linux-dmabuf-unstable-v1-server-protocol.h" #include "linux-explicit-synchronization.h" -static struct gl_renderer_interface *gl_renderer; +struct gl_renderer_interface *gl_renderer; static const char default_seat[] = "seat0"; @@ -136,9 +136,6 @@ drm_output_pageflip_timer_create(struct drm_output *output) static void drm_output_destroy(struct weston_output *output_base); -static void -drm_virtual_output_destroy(struct weston_output *output_base); - /** * Returns true if the plane can be used on the given output for its current * repaint cycle. @@ -331,7 +328,7 @@ drm_output_render_pixman(struct drm_output_state *state, return drm_fb_ref(output->dumb[output->current_image]); } -static void +void drm_output_render(struct drm_output_state *state, pixman_region32_t *damage) { struct drm_output *output = state->output; @@ -630,10 +627,6 @@ drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data) b->repaint_data = NULL; } -static int -drm_output_init_egl(struct drm_output *output, struct drm_backend *b); -static void -drm_output_fini_egl(struct drm_output *output); static int drm_output_init_pixman(struct drm_output *output, struct drm_backend *b); static void @@ -984,63 +977,6 @@ drm_plane_destroy(struct drm_plane *plane) free(plane); } -/** - * Create a drm_plane for virtual output - * - * Call drm_virtual_plane_destroy to clean up the plane. - * - * @param b DRM compositor backend - * @param output Output to create internal plane for - */ -static struct drm_plane * -drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output) -{ - struct drm_plane *plane; - - /* num of formats is one */ - plane = zalloc(sizeof(*plane) + sizeof(plane->formats[0])); - if (!plane) { - weston_log("%s: out of memory\n", __func__); - return NULL; - } - - plane->type = WDRM_PLANE_TYPE_PRIMARY; - plane->backend = b; - plane->state_cur = drm_plane_state_alloc(NULL, plane); - plane->state_cur->complete = true; - plane->formats[0].format = output->gbm_format; - plane->count_formats = 1; - if ((output->gbm_bo_flags & GBM_BO_USE_LINEAR) && b->fb_modifiers) { - uint64_t *modifiers = zalloc(sizeof *modifiers); - if (modifiers) { - *modifiers = DRM_FORMAT_MOD_LINEAR; - plane->formats[0].modifiers = modifiers; - plane->formats[0].count_modifiers = 1; - } - } - - weston_plane_init(&plane->base, b->compositor, 0, 0); - wl_list_insert(&b->plane_list, &plane->link); - - return plane; -} - -/** - * Destroy one DRM plane - * - * @param plane Plane to deallocate (will be freed) - */ -static void -drm_virtual_plane_destroy(struct drm_plane *plane) -{ - drm_plane_state_free(plane->state_cur, true); - weston_plane_release(&plane->base); - wl_list_remove(&plane->link); - if (plane->formats[0].modifiers) - free(plane->formats[0].modifiers); - free(plane); -} - /** * Initialise sprites (overlay planes) * @@ -1335,7 +1271,7 @@ err: } /* Init output state that depends on gl or gbm */ -static int +int drm_output_init_egl(struct drm_output *output, struct drm_backend *b) { uint32_t format[2] = { @@ -1406,7 +1342,7 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b) return 0; } -static void +void drm_output_fini_egl(struct drm_output *output) { struct drm_backend *b = to_drm_backend(output->base.compositor); @@ -1588,7 +1524,7 @@ drm_output_detach_head(struct weston_output *output_base, weston_output_schedule_repaint(output_base); } -static int +int parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format) { const struct pixel_format_info *pinfo; @@ -3107,271 +3043,12 @@ renderer_switch_binding(struct weston_keyboard *keyboard, switch_to_gl_renderer(b); } -static int -drm_virtual_output_start_repaint_loop(struct weston_output *output_base) -{ - weston_output_finish_frame(output_base, NULL, - WP_PRESENTATION_FEEDBACK_INVALID); - - return 0; -} - -static int -drm_virtual_output_submit_frame(struct drm_output *output, - struct drm_fb *fb) -{ - struct drm_backend *b = to_drm_backend(output->base.compositor); - int fd, ret; - - assert(fb->num_planes == 1); - ret = drmPrimeHandleToFD(b->drm.fd, fb->handles[0], DRM_CLOEXEC, &fd); - if (ret) { - weston_log("drmPrimeHandleFD failed, errno=%d\n", errno); - return -1; - } - - drm_fb_ref(fb); - ret = output->virtual_submit_frame(&output->base, fd, fb->strides[0], - fb); - if (ret < 0) { - drm_fb_unref(fb); - close(fd); - } - return ret; -} - -static int -drm_virtual_output_repaint(struct weston_output *output_base, - pixman_region32_t *damage, - void *repaint_data) -{ - struct drm_pending_state *pending_state = repaint_data; - struct drm_output_state *state = NULL; - struct drm_output *output = to_drm_output(output_base); - struct drm_plane *scanout_plane = output->scanout_plane; - struct drm_plane_state *scanout_state; - - assert(output->virtual); - - if (output->disable_pending || output->destroy_pending) - goto err; - - /* Drop frame if there isn't free buffers */ - if (!gbm_surface_has_free_buffers(output->gbm_surface)) { - weston_log("%s: Drop frame!!\n", __func__); - return -1; - } - - assert(!output->state_last); - - /* If planes have been disabled in the core, we might not have - * hit assign_planes at all, so might not have valid output state - * here. */ - state = drm_pending_state_get_output(pending_state, output); - if (!state) - state = drm_output_state_duplicate(output->state_cur, - pending_state, - DRM_OUTPUT_STATE_CLEAR_PLANES); - - drm_output_render(state, damage); - scanout_state = drm_output_state_get_plane(state, scanout_plane); - if (!scanout_state || !scanout_state->fb) - goto err; - - if (drm_virtual_output_submit_frame(output, scanout_state->fb) < 0) - goto err; - - return 0; - -err: - drm_output_state_free(state); - return -1; -} - -static void -drm_virtual_output_deinit(struct weston_output *base) -{ - struct drm_output *output = to_drm_output(base); - - drm_output_fini_egl(output); - - drm_virtual_plane_destroy(output->scanout_plane); -} - -static void -drm_virtual_output_destroy(struct weston_output *base) -{ - struct drm_output *output = to_drm_output(base); - - assert(output->virtual); - - if (output->base.enabled) - drm_virtual_output_deinit(&output->base); - - weston_output_release(&output->base); - - drm_output_state_free(output->state_cur); - - free(output); -} - -static int -drm_virtual_output_enable(struct weston_output *output_base) -{ - struct drm_output *output = to_drm_output(output_base); - struct drm_backend *b = to_drm_backend(output_base->compositor); - - assert(output->virtual); - - if (b->use_pixman) { - weston_log("Not support pixman renderer on Virtual output\n"); - goto err; - } - - if (!output->virtual_submit_frame) { - weston_log("The virtual_submit_frame hook is not set\n"); - goto err; - } - - output->scanout_plane = drm_virtual_plane_create(b, output); - if (!output->scanout_plane) { - weston_log("Failed to find primary plane for output %s\n", - output->base.name); - return -1; - } - - if (drm_output_init_egl(output, b) < 0) { - weston_log("Failed to init output gl state\n"); - goto err; - } - - output->base.start_repaint_loop = drm_virtual_output_start_repaint_loop; - output->base.repaint = drm_virtual_output_repaint; - output->base.assign_planes = drm_assign_planes; - output->base.set_dpms = NULL; - output->base.switch_mode = NULL; - output->base.gamma_size = 0; - output->base.set_gamma = NULL; - - weston_compositor_stack_plane(b->compositor, - &output->scanout_plane->base, - &b->compositor->primary_plane); - - return 0; -err: - return -1; -} - -static int -drm_virtual_output_disable(struct weston_output *base) -{ - struct drm_output *output = to_drm_output(base); - - assert(output->virtual); - - if (output->base.enabled) - drm_virtual_output_deinit(&output->base); - - return 0; -} - -static struct weston_output * -drm_virtual_output_create(struct weston_compositor *c, char *name) -{ - struct drm_output *output; - - output = zalloc(sizeof *output); - if (!output) - return NULL; - - output->virtual = true; - output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING; - - weston_output_init(&output->base, c, name); - - output->base.enable = drm_virtual_output_enable; - output->base.destroy = drm_virtual_output_destroy; - output->base.disable = drm_virtual_output_disable; - output->base.attach_head = NULL; - - output->state_cur = drm_output_state_alloc(output, NULL); - - weston_compositor_add_pending_output(&output->base, c); - - return &output->base; -} - -static uint32_t -drm_virtual_output_set_gbm_format(struct weston_output *base, - const char *gbm_format) -{ - struct drm_output *output = to_drm_output(base); - struct drm_backend *b = to_drm_backend(base->compositor); - - if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1) - output->gbm_format = b->gbm_format; - - return output->gbm_format; -} - -static void -drm_virtual_output_set_submit_frame_cb(struct weston_output *output_base, - submit_frame_cb cb) -{ - struct drm_output *output = to_drm_output(output_base); - - output->virtual_submit_frame = cb; -} - -static int -drm_virtual_output_get_fence_fd(struct weston_output *output_base) -{ - return gl_renderer->create_fence_fd(output_base); -} - -static void -drm_virtual_output_buffer_released(struct drm_fb *fb) -{ - drm_fb_unref(fb); -} - -static void -drm_virtual_output_finish_frame(struct weston_output *output_base, - struct timespec *stamp, - uint32_t presented_flags) -{ - struct drm_output *output = to_drm_output(output_base); - struct drm_plane_state *ps; - - wl_list_for_each(ps, &output->state_cur->plane_list, link) - ps->complete = true; - - drm_output_state_free(output->state_last); - output->state_last = NULL; - - weston_output_finish_frame(&output->base, stamp, presented_flags); - - /* We can't call this from frame_notify, because the output's - * repaint needed flag is cleared just after that */ - if (output->recorder) - weston_output_schedule_repaint(&output->base); -} - static const struct weston_drm_output_api api = { drm_output_set_mode, drm_output_set_gbm_format, drm_output_set_seat, }; -static const struct weston_drm_virtual_output_api virt_api = { - drm_virtual_output_create, - drm_virtual_output_set_gbm_format, - drm_virtual_output_set_submit_frame_cb, - drm_virtual_output_get_fence_fd, - drm_virtual_output_buffer_released, - drm_virtual_output_finish_frame -}; - static struct drm_backend * drm_backend_create(struct weston_compositor *compositor, struct weston_drm_backend_config *config) @@ -3549,9 +3226,7 @@ drm_backend_create(struct weston_compositor *compositor, goto err_udev_monitor; } - ret = weston_plugin_api_register(compositor, - WESTON_DRM_VIRTUAL_OUTPUT_API_NAME, - &virt_api, sizeof(virt_api)); + ret = drm_backend_init_virtual_output_api(compositor); if (ret < 0) { weston_log("Failed to register virtual output API.\n"); goto err_udev_monitor; diff --git a/libweston/backend-drm/meson.build b/libweston/backend-drm/meson.build index 6d6a7239..ee92f125 100644 --- a/libweston/backend-drm/meson.build +++ b/libweston/backend-drm/meson.build @@ -70,6 +70,11 @@ if get_option('backend-drm-screencast-vaapi') config_h.set('BUILD_VAAPI_RECORDER', '1') endif +if get_option('remoting') + srcs_drm += 'drm-virtual.c' + config_h.set('BUILD_DRM_VIRTUAL', '1') +endif + if dep_libdrm.version().version_compare('>= 2.4.71') config_h.set('HAVE_DRM_ADDFB2_MODIFIERS', '1') endif