compositor-drm: Add Support virtual output
Add support virtual output for streaming image to remote output by remoting-plugin which will be added by the patch: "Add remoting plugin for output streaming." The gbm bo of virtual output is the linear format. Virtual output is implemented based on a patch by Grigory Kletsko <grigory.kletsko@cogentembedded.com>. Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
This commit is contained in:
+360
-1
@@ -74,6 +74,10 @@
|
|||||||
#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
|
#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef GBM_BO_USE_LINEAR
|
||||||
|
#define GBM_BO_USE_LINEAR (1 << 4)
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A small wrapper to print information into the 'drm-backend' debug scope.
|
* A small wrapper to print information into the 'drm-backend' debug scope.
|
||||||
*
|
*
|
||||||
@@ -547,6 +551,10 @@ struct drm_output {
|
|||||||
struct wl_listener recorder_frame_listener;
|
struct wl_listener recorder_frame_listener;
|
||||||
|
|
||||||
struct wl_event_source *pageflip_timer;
|
struct wl_event_source *pageflip_timer;
|
||||||
|
|
||||||
|
bool virtual;
|
||||||
|
|
||||||
|
submit_frame_cb virtual_submit_frame;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const aspect_ratio_as_string[] = {
|
static const char *const aspect_ratio_as_string[] = {
|
||||||
@@ -859,6 +867,9 @@ drm_output_update_msc(struct drm_output *output, unsigned int seq);
|
|||||||
static void
|
static void
|
||||||
drm_output_destroy(struct weston_output *output_base);
|
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
|
* Returns true if the plane can be used on the given output for its current
|
||||||
* repaint cycle.
|
* repaint cycle.
|
||||||
@@ -868,6 +879,9 @@ drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
|
|||||||
{
|
{
|
||||||
assert(plane->state_cur);
|
assert(plane->state_cur);
|
||||||
|
|
||||||
|
if (output->virtual)
|
||||||
|
return false;
|
||||||
|
|
||||||
/* The plane still has a request not yet completed by the kernel. */
|
/* The plane still has a request not yet completed by the kernel. */
|
||||||
if (!plane->state_cur->complete)
|
if (!plane->state_cur->complete)
|
||||||
return false;
|
return false;
|
||||||
@@ -2668,6 +2682,8 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
wl_list_for_each(output_state, &pending_state->output_list, link) {
|
wl_list_for_each(output_state, &pending_state->output_list, link) {
|
||||||
|
if (output_state->output->virtual)
|
||||||
|
continue;
|
||||||
if (mode == DRM_STATE_APPLY_SYNC)
|
if (mode == DRM_STATE_APPLY_SYNC)
|
||||||
assert(output_state->dpms == WESTON_DPMS_OFF);
|
assert(output_state->dpms == WESTON_DPMS_OFF);
|
||||||
ret |= drm_output_apply_state_atomic(output_state, req, &flags);
|
ret |= drm_output_apply_state_atomic(output_state, req, &flags);
|
||||||
@@ -2777,6 +2793,12 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
|
|||||||
struct drm_output *output = output_state->output;
|
struct drm_output *output = output_state->output;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (output->virtual) {
|
||||||
|
drm_output_assign_state(output_state,
|
||||||
|
DRM_STATE_APPLY_ASYNC);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ret = drm_output_apply_state_legacy(output_state);
|
ret = drm_output_apply_state_legacy(output_state);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
weston_log("Couldn't apply state for output %s\n",
|
weston_log("Couldn't apply state for output %s\n",
|
||||||
@@ -2855,6 +2877,8 @@ drm_output_repaint(struct weston_output *output_base,
|
|||||||
struct drm_output_state *state = NULL;
|
struct drm_output_state *state = NULL;
|
||||||
struct drm_plane_state *scanout_state;
|
struct drm_plane_state *scanout_state;
|
||||||
|
|
||||||
|
assert(!output->virtual);
|
||||||
|
|
||||||
if (output->disable_pending || output->destroy_pending)
|
if (output->disable_pending || output->destroy_pending)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@@ -3729,7 +3753,7 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
|
|||||||
drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n",
|
drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n",
|
||||||
output_base->name, (unsigned long) output_base->id);
|
output_base->name, (unsigned long) output_base->id);
|
||||||
|
|
||||||
if (!b->sprites_are_broken) {
|
if (!b->sprites_are_broken && !output->virtual) {
|
||||||
state = drm_output_propose_state(output_base, pending_state,
|
state = drm_output_propose_state(output_base, pending_state,
|
||||||
DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
|
DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
|
||||||
if (!state) {
|
if (!state) {
|
||||||
@@ -4448,6 +4472,63 @@ drm_plane_destroy(struct drm_plane *plane)
|
|||||||
free(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) {
|
||||||
|
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)
|
* Initialise sprites (overlay planes)
|
||||||
*
|
*
|
||||||
@@ -4681,6 +4762,8 @@ drm_output_init_backlight(struct drm_output *output)
|
|||||||
*
|
*
|
||||||
* If we are called as part of repaint, we simply set the relevant bit in
|
* If we are called as part of repaint, we simply set the relevant bit in
|
||||||
* state and return.
|
* state and return.
|
||||||
|
*
|
||||||
|
* This function is never called on a virtual output.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
|
drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
|
||||||
@@ -4691,6 +4774,8 @@ drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
|
|||||||
struct drm_output_state *state;
|
struct drm_output_state *state;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
assert(!output->virtual);
|
||||||
|
|
||||||
if (output->state_cur->dpms == level)
|
if (output->state_cur->dpms == level)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -5591,6 +5676,9 @@ drm_output_set_mode(struct weston_output *base,
|
|||||||
|
|
||||||
struct drm_mode *current;
|
struct drm_mode *current;
|
||||||
|
|
||||||
|
if (output->virtual)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (drm_output_update_modelist_from_heads(output) < 0)
|
if (drm_output_update_modelist_from_heads(output) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -5948,6 +6036,8 @@ drm_output_enable(struct weston_output *base)
|
|||||||
drmModeRes *resources;
|
drmModeRes *resources;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
assert(!output->virtual);
|
||||||
|
|
||||||
resources = drmModeGetResources(b->drm.fd);
|
resources = drmModeGetResources(b->drm.fd);
|
||||||
if (!resources) {
|
if (!resources) {
|
||||||
weston_log("drmModeGetResources failed\n");
|
weston_log("drmModeGetResources failed\n");
|
||||||
@@ -6045,6 +6135,8 @@ drm_output_destroy(struct weston_output *base)
|
|||||||
struct drm_output *output = to_drm_output(base);
|
struct drm_output *output = to_drm_output(base);
|
||||||
struct drm_backend *b = to_drm_backend(base->compositor);
|
struct drm_backend *b = to_drm_backend(base->compositor);
|
||||||
|
|
||||||
|
assert(!output->virtual);
|
||||||
|
|
||||||
if (output->page_flip_pending || output->vblank_pending ||
|
if (output->page_flip_pending || output->vblank_pending ||
|
||||||
output->atomic_complete_pending) {
|
output->atomic_complete_pending) {
|
||||||
output->destroy_pending = 1;
|
output->destroy_pending = 1;
|
||||||
@@ -6073,6 +6165,8 @@ drm_output_disable(struct weston_output *base)
|
|||||||
{
|
{
|
||||||
struct drm_output *output = to_drm_output(base);
|
struct drm_output *output = to_drm_output(base);
|
||||||
|
|
||||||
|
assert(!output->virtual);
|
||||||
|
|
||||||
if (output->page_flip_pending || output->vblank_pending ||
|
if (output->page_flip_pending || output->vblank_pending ||
|
||||||
output->atomic_complete_pending) {
|
output->atomic_complete_pending) {
|
||||||
output->disable_pending = 1;
|
output->disable_pending = 1;
|
||||||
@@ -6909,12 +7003,269 @@ renderer_switch_binding(struct weston_keyboard *keyboard,
|
|||||||
switch_to_gl_renderer(b);
|
switch_to_gl_renderer(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
drm_virtual_output_start_repaint_loop(struct weston_output *output_base)
|
||||||
|
{
|
||||||
|
weston_output_finish_frame(output_base, NULL,
|
||||||
|
WP_PRESENTATION_FEEDBACK_INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = {
|
static const struct weston_drm_output_api api = {
|
||||||
drm_output_set_mode,
|
drm_output_set_mode,
|
||||||
drm_output_set_gbm_format,
|
drm_output_set_gbm_format,
|
||||||
drm_output_set_seat,
|
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 *
|
static struct drm_backend *
|
||||||
drm_backend_create(struct weston_compositor *compositor,
|
drm_backend_create(struct weston_compositor *compositor,
|
||||||
struct weston_drm_backend_config *config)
|
struct weston_drm_backend_config *config)
|
||||||
@@ -7079,6 +7430,14 @@ drm_backend_create(struct weston_compositor *compositor,
|
|||||||
goto err_udev_monitor;
|
goto err_udev_monitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = weston_plugin_api_register(compositor,
|
||||||
|
WESTON_DRM_VIRTUAL_OUTPUT_API_NAME,
|
||||||
|
&virt_api, sizeof(virt_api));
|
||||||
|
if (ret < 0) {
|
||||||
|
weston_log("Failed to register virtual output API.\n");
|
||||||
|
goto err_udev_monitor;
|
||||||
|
}
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
|
|
||||||
err_udev_monitor:
|
err_udev_monitor:
|
||||||
|
|||||||
@@ -90,6 +90,79 @@ weston_drm_output_get_api(struct weston_compositor *compositor)
|
|||||||
return (const struct weston_drm_output_api *)api;
|
return (const struct weston_drm_output_api *)api;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define WESTON_DRM_VIRTUAL_OUTPUT_API_NAME "weston_drm_virtual_output_api_v1"
|
||||||
|
|
||||||
|
struct drm_fb;
|
||||||
|
typedef int (*submit_frame_cb)(struct weston_output *output, int fd,
|
||||||
|
int stride, struct drm_fb *buffer);
|
||||||
|
|
||||||
|
struct weston_drm_virtual_output_api {
|
||||||
|
/** Create virtual output.
|
||||||
|
* This is a low-level function, where the caller is expected to wrap
|
||||||
|
* the weston_output function pointers as necessary to make the virtual
|
||||||
|
* output useful. The caller must set up output make, model, serial,
|
||||||
|
* physical size, the mode list and current mode.
|
||||||
|
*
|
||||||
|
* Returns output on success, NULL on failure.
|
||||||
|
*/
|
||||||
|
struct weston_output* (*create_output)(struct weston_compositor *c,
|
||||||
|
char *name);
|
||||||
|
|
||||||
|
/** Set pixel format same as drm_output set_gbm_format().
|
||||||
|
*
|
||||||
|
* Returns the set format.
|
||||||
|
*/
|
||||||
|
uint32_t (*set_gbm_format)(struct weston_output *output,
|
||||||
|
const char *gbm_format);
|
||||||
|
|
||||||
|
/** Set a callback to be called when the DRM-backend has drawn a new
|
||||||
|
* frame and submits it for display.
|
||||||
|
* The callback will deliver a buffer to the virtual output's the
|
||||||
|
* owner and assumes the buffer is now reserved for the owner. The
|
||||||
|
* callback is called in virtual output repaint function.
|
||||||
|
* The caller must call buffer_released() and finish_frame().
|
||||||
|
*
|
||||||
|
* The callback parameters are output, FD and stride (bytes) of dmabuf,
|
||||||
|
* and buffer (drm_fb) pointer.
|
||||||
|
* The callback returns 0 on success, -1 on failure.
|
||||||
|
*
|
||||||
|
* The submit_frame_cb callback hook is responsible for closing the fd
|
||||||
|
* if it returns success. One needs to call the buffer release and
|
||||||
|
* finish frame functions if and only if this hook returns success.
|
||||||
|
*/
|
||||||
|
void (*set_submit_frame_cb)(struct weston_output *output,
|
||||||
|
submit_frame_cb cb);
|
||||||
|
|
||||||
|
/** Get fd for renderer fence.
|
||||||
|
* The returned fence signals when the renderer job has completed and
|
||||||
|
* the buffer is fully drawn.
|
||||||
|
*
|
||||||
|
* Returns fd on success, -1 on failure.
|
||||||
|
*/
|
||||||
|
int (*get_fence_sync_fd)(struct weston_output *output);
|
||||||
|
|
||||||
|
/** Notify that the caller has finished using buffer */
|
||||||
|
void (*buffer_released)(struct drm_fb *fb);
|
||||||
|
|
||||||
|
/** Notify finish frame
|
||||||
|
* This function allows the output repainting mechanism to advance to
|
||||||
|
* the next frame.
|
||||||
|
*/
|
||||||
|
void (*finish_frame)(struct weston_output *output,
|
||||||
|
struct timespec *stamp,
|
||||||
|
uint32_t presented_flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline const struct weston_drm_virtual_output_api *
|
||||||
|
weston_drm_virtual_output_get_api(struct weston_compositor *compositor)
|
||||||
|
{
|
||||||
|
const void *api;
|
||||||
|
api = weston_plugin_api_get(compositor,
|
||||||
|
WESTON_DRM_VIRTUAL_OUTPUT_API_NAME,
|
||||||
|
sizeof(struct weston_drm_virtual_output_api));
|
||||||
|
return (const struct weston_drm_virtual_output_api *)api;
|
||||||
|
}
|
||||||
|
|
||||||
/** The backend configuration struct.
|
/** The backend configuration struct.
|
||||||
*
|
*
|
||||||
* weston_drm_backend_config contains the configuration used by a DRM
|
* weston_drm_backend_config contains the configuration used by a DRM
|
||||||
|
|||||||
Reference in New Issue
Block a user