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 <stefan@agner.ch>
dev
Stefan Agner 5 years ago
parent 8d63e25963
commit 3654c673f8
  1. 25
      libweston/backend-drm/drm-internal.h
  2. 362
      libweston/backend-drm/drm-virtual.c
  3. 337
      libweston/backend-drm/drm.c
  4. 5
      libweston/backend-drm/meson.build

@ -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);

@ -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 <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#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));
}

@ -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;

@ -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

Loading…
Cancel
Save