weston/libweston/backend-drm/drm.c

4183 lines
112 KiB
C
Raw Normal View History

/*
* 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"
2011-04-12 15:34:32 +00:00
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
2012-04-10 04:11:50 +00:00
#include <linux/input.h>
#include <linux/vt.h>
#include <assert.h>
#include <sys/mman.h>
#include <time.h>
#include <poll.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <libudev.h>
2011-04-30 07:32:11 +00:00
#include <libweston/libweston.h>
#include <libweston/backend-drm.h>
#include <libweston/weston-log.h>
#include "drm-internal.h"
#include "shared/hash.h"
#include "shared/helpers.h"
compositor-drm: Allow instant start of repaint loop. (v4) drm_output_start_repaint_loop() incurred a delay of one refresh cycle by using a no-op page-flip to get an accurate vblank timestamp as reference. This causes unwanted lag whenever Weston exited its repaint loop, e.g., whenever an application wants to repaint with less than full video refresh rate but still minimum lag. Try to use the drmWaitVblank ioctl to get a proper timestamp instantaneously without lag. If that does not work, fall back to the old method of idle page-flip. This optimization will work on any drm/kms driver which supports high precision vblank timestamping. As of Linux 4.0 these would be intel, radeon and nouveau on all their supported gpu's. On kms drivers without instant high precision timestamping support, the kernel is supposed to return a timestamp of zero when calling drmWaitVblank() to query the current vblank count and time iff vblank irqs are currently disabled, because the only way to get a valid timestamp on such kms drivers is to enable vblank interrupts and then wait a bit for the next vblank irq to take a new valid timestamp. The caller is supposed to poll until at next vblank irq it gets a valid non-zero timestamp if it needs a timestamp. This zero-timestamp signalling works up to Linux 3.17, but got broken due to a regression in Linux 3.18 and later. On Linux 3.18+ with kms drivers that don't have high precision timestamping, the kernel erroneously returns a stale timestamp from an earlier vblank, ie. the vblank count and timestamp are mismatched. A patch is under way to fix this, but to deal with broken kernels, we also check non-zero timestamps if they are more than one refresh duration in the past, as this indicates a stale/invalid timestamp, so we need to take the page-flip fallback for restarting the repaint loop. v2: Implement review suggestions by Pekka Paalanen, especially extend the commit message to describe when and why the instant restart won't work due to missing Linux kernel functionality or a Linux kernel regression. Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> v3: Fix timespec_to_nsec() which was computing picoseconds, use the new timespec-util.h helpers. v4: Rebased to master, split long lines. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2015-06-21 19:25:14 +00:00
#include "shared/timespec-util.h"
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
#include "shared/string-helpers.h"
#include "shared/weston-drm-fourcc.h"
#include "output-capture.h"
#include "pixman-renderer.h"
#include "pixel-formats.h"
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
#include "libbacklight.h"
#include "libinput-seat.h"
#include "launcher-util.h"
#include "vaapi-recorder.h"
#include "presentation-time-server-protocol.h"
#include "linux-dmabuf.h"
#include "linux-dmabuf-unstable-v1-server-protocol.h"
libweston: Support zwp_surface_synchronization_v1.set_acquire_fence Implement the set_acquire_fence request of the zwp_surface_synchronization_v1 interface. The implementation uses the acquire fence in two ways: 1. If the associated buffer is used as GL render source, an EGLSyncKHR is created from the fence and used to synchronize access. 2. If the associated buffer is used as a plane framebuffer, the acquire fence is treated as an in-fence for the atomic commit operation. If in-fences are not supported and the buffer has an acquire fence, we don't consider it for plane placement. If the used compositor/renderer doesn't support explicit synchronization, we don't advertise the protocol at all. Currently only the DRM and X11 backends when using the GL renderer advertise the protocol for production use. Issues for discussion --------------------- a. Currently, a server-side wait of EGLSyncKHR is performed before using the EGLImage/texture during rendering. Unfortunately, it's not clear from the specs whether this is generally safe to do, or we need to sync before glEGLImageTargetTexture2DOES. The exception is TEXTURE_EXTERNAL_OES where the spec mentions it's enough to sync and then glBindTexture for any changes to take effect. Changes in v5: - Meson support. - Make explicit sync server error reporting more generic, supporting all explicit sync related interfaces not just wp_linux_surface_synchronization. - Fix typo in warning for missing EGL_KHR_wait_sync extension. - Support minor version 2 of the explicit sync protocol (i.e., support fences for opaque EGL buffers). Changes in v4: - Introduce and use fd_clear and and fd_move helpers. - Don't check for a valid buffer when updating surface acquire fence fd from state. - Assert that pending state acquire fence fd is always clear after a commit. - Clarify that WESTON_CAP_EXPLICIT_SYNC applies to just the renderer. - Check for EGL_KHR_wait_sync before using eglWaitSyncKHR. - Dup the acquire fence before passing to EGL. Changes in v3: - Keep acquire_fence_fd in surface instead of buffer. - Clarify that WESTON_CAP_EXPLICIT_SYNC applies to both backend and renderer. - Move comment about non-ownership of in_fence_fd to struct drm_plane_state definition. - Assert that we don't try to use planes with in-fences when using the legacy KMS API. - Remove unnecessary info from wayland error messages. - Handle acquire fence for subsurface commits. - Guard against self-update in fd_update. - Disconnect the client if acquire fence EGLSyncKHR creation or wait fails. - Use updated protocol interface names. - User correct format specifier for resource ids. - Advertise protocol for X11 backend with GL renderer. Changes in v2: - Remove sync file wait fallbacks. - Raise UNSUPPORTED_BUFFER error at commit if we have an acquire fence, but the committed buffer is not a valid linux_dmabuf. - Don't put buffers with in-fences on planes that don't support in-fences. - Don't advertise explicit sync protocol if backend does not support explicit sync. Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
2018-10-19 09:14:11 +00:00
#include "linux-explicit-synchronization.h"
static const char default_seat[] = "seat0";
static void
drm_backend_create_faked_zpos(struct drm_device *device)
{
struct drm_backend *b = device->backend;
struct drm_plane *plane, *tmp;
struct wl_list tmp_list;
uint64_t zpos = 0ULL;
uint64_t zpos_min_primary;
uint64_t zpos_min_overlay;
uint64_t zpos_min_cursor;
/* if the property is there, bail out sooner */
wl_list_for_each(plane, &device->plane_list, link) {
if (plane->props[WDRM_PLANE_ZPOS].prop_id != 0)
return;
}
drm_debug(b, "[drm-backend] zpos property not found. "
"Using invented immutable zpos values:\n");
wl_list_init(&tmp_list);
wl_list_insert_list(&tmp_list, &device->plane_list);
wl_list_init(&device->plane_list);
zpos_min_primary = zpos;
wl_list_for_each_safe(plane, tmp, &tmp_list, link) {
if (plane->type != WDRM_PLANE_TYPE_PRIMARY)
continue;
plane->zpos_min = zpos_min_primary;
plane->zpos_max = zpos_min_primary;
wl_list_remove(&plane->link);
wl_list_insert(&device->plane_list, &plane->link);
zpos++;
drm_debug(b, "\t[plane] %s plane %d, zpos_min %"PRIu64", "
"zpos_max %"PRIu64"\n",
drm_output_get_plane_type_name(plane),
plane->plane_id, plane->zpos_min, plane->zpos_max);
}
zpos_min_overlay = zpos;
wl_list_for_each_safe(plane, tmp, &tmp_list, link) {
if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
continue;
plane->zpos_min = zpos_min_overlay;
plane->zpos_max = zpos_min_overlay;
wl_list_remove(&plane->link);
wl_list_insert(&device->plane_list, &plane->link);
zpos++;
drm_debug(b, "\t[plane] %s plane %d, zpos_min %"PRIu64", "
"zpos_max %"PRIu64"\n",
drm_output_get_plane_type_name(plane),
plane->plane_id, plane->zpos_min, plane->zpos_max);
}
zpos_min_cursor = zpos;
wl_list_for_each_safe(plane, tmp, &tmp_list, link) {
if (plane->type != WDRM_PLANE_TYPE_CURSOR)
continue;
plane->zpos_min = zpos_min_cursor;
plane->zpos_max = zpos_min_cursor;
wl_list_remove(&plane->link);
wl_list_insert(&device->plane_list, &plane->link);
zpos++;
drm_debug(b, "\t[plane] %s plane %d, zpos_min %"PRIu64", "
"zpos_max %"PRIu64"\n",
drm_output_get_plane_type_name(plane),
plane->plane_id, plane->zpos_min, plane->zpos_max);
}
assert(wl_list_empty(&tmp_list));
}
compositor-drm: pageflip timeout implementation Weston will not repaint until previous update has been acked by a pageflip event coming from the drm driver. However, some buggy drivers won’t return those events or will stop sending them at some point and Weston output repaints will completely freeze. To ease developers’ task in testing their drivers, this patch makes compositor-drm use a timer to detect cases where those pageflip events stop coming. This timeout implementation is software only and includes basic features usually found in a watchdog. We simply exit Weston gracefully with a log message and an exit code when the timout is reached. The timeout value can be set via weston.ini by adding a pageflip-timeout=<MILLISECONDS> entry under [core] section. Setting it to 0 disables the timeout feature. v2: - Made sure we would get both the pageflip and the vblank events before stopping the timer. - Reordered the error and success cases in drm_output_pageflip_timer_create() to be more in line with the rest of the code. v3: - Reordered (de)arming of the timer with the code around it to avoid it being rearmed before the current dearming. - Return the proper value for the dispatcher in the pageflip_timeout callback. - Also display the output name in case the timer fires. v4: - Reordered a forgotten timer rearming after its drmModePageFlip(). Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=83884 Signed-off-by: Frederic Plourde <frederic.plourde at collabora.co.uk> Signed-off-by: Emmanuel Gil Peyrot <emmanuel.peyrot@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2017-03-07 13:27:54 +00:00
static int
pageflip_timeout(void *data) {
/*
* Our timer just went off, that means we're not receiving drm
* page flip events anymore for that output. Let's gracefully exit
* weston with a return value so devs can debug what's going on.
*/
struct drm_output *output = data;
struct weston_compositor *compositor = output->base.compositor;
weston_log("Pageflip timeout reached on output %s, your "
"driver is probably buggy! Exiting.\n",
output->base.name);
weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
return 0;
}
/* Creates the pageflip timer. Note that it isn't armed by default */
static int
drm_output_pageflip_timer_create(struct drm_output *output)
{
struct wl_event_loop *loop = NULL;
struct weston_compositor *ec = output->base.compositor;
loop = wl_display_get_event_loop(ec->wl_display);
assert(loop);
output->pageflip_timer = wl_event_loop_add_timer(loop,
pageflip_timeout,
output);
if (output->pageflip_timer == NULL) {
weston_log("creating drm pageflip timer failed: %s\n",
strerror(errno));
compositor-drm: pageflip timeout implementation Weston will not repaint until previous update has been acked by a pageflip event coming from the drm driver. However, some buggy drivers won’t return those events or will stop sending them at some point and Weston output repaints will completely freeze. To ease developers’ task in testing their drivers, this patch makes compositor-drm use a timer to detect cases where those pageflip events stop coming. This timeout implementation is software only and includes basic features usually found in a watchdog. We simply exit Weston gracefully with a log message and an exit code when the timout is reached. The timeout value can be set via weston.ini by adding a pageflip-timeout=<MILLISECONDS> entry under [core] section. Setting it to 0 disables the timeout feature. v2: - Made sure we would get both the pageflip and the vblank events before stopping the timer. - Reordered the error and success cases in drm_output_pageflip_timer_create() to be more in line with the rest of the code. v3: - Reordered (de)arming of the timer with the code around it to avoid it being rearmed before the current dearming. - Return the proper value for the dispatcher in the pageflip_timeout callback. - Also display the output name in case the timer fires. v4: - Reordered a forgotten timer rearming after its drmModePageFlip(). Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=83884 Signed-off-by: Frederic Plourde <frederic.plourde at collabora.co.uk> Signed-off-by: Emmanuel Gil Peyrot <emmanuel.peyrot@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2017-03-07 13:27:54 +00:00
return -1;
}
return 0;
}
/**
* Returns true if the plane can be used on the given output for its current
* repaint cycle.
*/
bool
drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
{
assert(plane->state_cur);
if (output->virtual)
return false;
/* The plane still has a request not yet completed by the kernel. */
if (!plane->state_cur->complete)
return false;
/* The plane is still active on another output. */
if (plane->state_cur->output && plane->state_cur->output != output)
return false;
/* Check whether the plane can be used with this CRTC; possible_crtcs
* is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
return !!(plane->possible_crtcs & (1 << output->crtc->pipe));
}
struct drm_crtc *
drm_crtc_find(struct drm_device *device, uint32_t crtc_id)
{
struct drm_crtc *crtc;
wl_list_for_each(crtc, &device->crtc_list, link) {
if (crtc->crtc_id == crtc_id)
return crtc;
}
return NULL;
}
struct drm_head *
drm_head_find_by_connector(struct drm_backend *backend, struct drm_device *device, uint32_t connector_id)
{
struct weston_head *base;
struct drm_head *head;
wl_list_for_each(base,
&backend->compositor->head_list, compositor_link) {
head = to_drm_head(base);
if (!head)
continue;
if (head->connector.device != device)
continue;
if (head->connector.connector_id != connector_id)
continue;
return head;
}
return NULL;
}
static struct drm_writeback *
drm_writeback_find_by_connector(struct drm_device *device, uint32_t connector_id)
{
struct drm_writeback *writeback;
wl_list_for_each(writeback, &device->writeback_connector_list, link) {
if (writeback->connector.connector_id == connector_id)
return writeback;
}
return NULL;
}
/**
* Get output state to disable output
*
* Returns a pointer to an output_state object which can be used to disable
* an output (e.g. DPMS off).
*
* @param pending_state The pending state object owning this update
* @param output The output to disable
* @returns A drm_output_state to disable the output
*/
static struct drm_output_state *
drm_output_get_disable_state(struct drm_pending_state *pending_state,
struct drm_output *output)
{
struct drm_output_state *output_state;
output_state = drm_output_state_duplicate(output->state_cur,
pending_state,
DRM_OUTPUT_STATE_CLEAR_PLANES);
output_state->dpms = WESTON_DPMS_OFF;
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
output_state->protection = WESTON_HDCP_DISABLE;
return output_state;
}
static int
drm_output_apply_mode(struct drm_output *output);
/**
* Mark a drm_output_state (the output's last state) as complete. This handles
* any post-completion actions such as updating the repaint timer, disabling the
* output, and finally freeing the state.
*/
void
drm_output_update_complete(struct drm_output *output, uint32_t flags,
unsigned int sec, unsigned int usec)
{
struct drm_device *device = output->device;
struct drm_plane_state *ps;
struct timespec ts;
/* Stop the pageflip timer instead of rearming it here */
if (output->pageflip_timer)
wl_event_source_timer_update(output->pageflip_timer, 0);
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;
if (output->destroy_pending) {
output->destroy_pending = false;
output->disable_pending = false;
output->dpms_off_pending = false;
output->mode_switch_pending = false;
drm_output_destroy(&output->base);
return;
} else if (output->disable_pending) {
output->disable_pending = false;
output->dpms_off_pending = false;
output->mode_switch_pending = false;
weston_output_disable(&output->base);
return;
} else if (output->dpms_off_pending) {
struct drm_pending_state *pending = drm_pending_state_alloc(device);
output->dpms_off_pending = false;
output->mode_switch_pending = false;
drm_output_get_disable_state(pending, output);
drm_pending_state_apply_sync(pending);
} else if (output->mode_switch_pending) {
output->mode_switch_pending = false;
drm_output_apply_mode(output);
}
if (output->state_cur->dpms == WESTON_DPMS_OFF &&
output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
/* DPMS can happen to us either in the middle of a repaint
* cycle (when we have painted fresh content, only to throw it
* away for DPMS off), or at any other random point. If the
* latter is true, then we cannot go through finish_frame,
* because the repaint machinery does not expect this. */
return;
}
if (output->state_cur->tear)
flags |= WESTON_FINISH_FRAME_TEARING;
ts.tv_sec = sec;
ts.tv_nsec = usec * 1000;
if (output->state_cur->dpms != WESTON_DPMS_OFF)
weston_output_finish_frame(&output->base, &ts, flags);
else
weston_output_finish_frame(&output->base, NULL,
WP_PRESENTATION_FEEDBACK_INVALID);
/* 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 struct drm_fb *
drm_output_render_pixman(struct drm_output_state *state,
pixman_region32_t *damage)
{
struct drm_output *output = state->output;
struct weston_compositor *ec = output->base.compositor;
output->current_image ^= 1;
ec->renderer->repaint_output(&output->base, damage,
output->renderbuffer[output->current_image]);
return drm_fb_ref(output->dumb[output->current_image]);
}
void
drm_output_render(struct drm_output_state *state)
{
struct drm_output *output = state->output;
struct drm_device *device = output->device;
struct weston_compositor *c = output->base.compositor;
struct drm_plane_state *scanout_state;
struct drm_plane *scanout_plane = output->scanout_plane;
struct drm_property_info *damage_info =
&scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
struct drm_fb *fb;
pixman_region32_t damage, scanout_damage;
pixman_box32_t *rects;
int n_rects;
/* If we already have a client buffer promoted to scanout, then we don't
* want to render. */
scanout_state = drm_output_state_get_plane(state, scanout_plane);
if (scanout_state->fb)
return;
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(&output->base, &damage);
/*
* If we don't have any damage on the primary plane, and we already
* have a renderer buffer active, we can reuse it; else we pass
* the damaged region into the renderer to re-render the affected
* area. But, we still have to call the renderer anyway if any screen
* capture is pending, otherwise the capture will not complete.
*/
if (!pixman_region32_not_empty(&damage) &&
wl_list_empty(&output->base.frame_signal.listener_list) &&
!weston_output_has_renderer_capture_tasks(&output->base) &&
scanout_plane->state_cur->fb &&
(scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) {
fb = drm_fb_ref(scanout_plane->state_cur->fb);
} else if (c->renderer->type == WESTON_RENDERER_PIXMAN) {
fb = drm_output_render_pixman(state, &damage);
} else {
fb = drm_output_render_gl(state, &damage);
}
if (!fb) {
drm_plane_state_put_back(scanout_state);
goto out;
}
scanout_state->fb = fb;
scanout_state->output = output;
scanout_state->src_x = 0;
scanout_state->src_y = 0;
scanout_state->src_w = fb->width << 16;
scanout_state->src_h = fb->height << 16;
scanout_state->dest_x = 0;
scanout_state->dest_y = 0;
scanout_state->dest_w = output->base.current_mode->width;
scanout_state->dest_h = output->base.current_mode->height;
scanout_state->zpos = scanout_plane->zpos_min;
/* Don't bother calculating plane damage if the plane doesn't support it */
if (damage_info->prop_id == 0)
goto out;
pixman_region32_init(&scanout_damage);
weston_region_global_to_output(&scanout_damage,
&output->base,
&damage);
assert(scanout_state->damage_blob_id == 0);
rects = pixman_region32_rectangles(&scanout_damage, &n_rects);
/*
* If this function fails, the blob id should still be 0.
* This tells the kernel there is no damage information, which means
* that it will consider the whole plane damaged. While this may
* affect efficiency, it should still produce correct results.
*/
drmModeCreatePropertyBlob(device->drm.fd, rects,
sizeof(*rects) * n_rects,
&scanout_state->damage_blob_id);
pixman_region32_fini(&scanout_damage);
out:
pixman_region32_fini(&damage);
}
static uint32_t
drm_connector_get_possible_crtcs_mask(struct drm_connector *connector)
{
struct drm_device *device = connector->device;
uint32_t possible_crtcs = 0;
drmModeConnector *conn = connector->conn;
drmModeEncoder *encoder;
int i;
for (i = 0; i < conn->count_encoders; i++) {
encoder = drmModeGetEncoder(device->drm.fd,
conn->encoders[i]);
if (!encoder)
continue;
possible_crtcs |= encoder->possible_crtcs;
drmModeFreeEncoder(encoder);
}
return possible_crtcs;
}
static struct drm_writeback *
drm_output_find_compatible_writeback(struct drm_output *output)
{
struct drm_crtc *crtc;
struct drm_writeback *wb;
bool in_use;
uint32_t possible_crtcs;
wl_list_for_each(wb, &output->device->writeback_connector_list, link) {
/* Another output may be using the writeback connector. */
in_use = false;
wl_list_for_each(crtc, &output->device->crtc_list, link) {
if (crtc->output && crtc->output->wb_state &&
crtc->output->wb_state->wb == wb) {
in_use = true;
break;
}
}
if (in_use)
continue;
/* Is the writeback connector compatible with the CRTC? */
possible_crtcs =
drm_connector_get_possible_crtcs_mask(&wb->connector);
if (!(possible_crtcs & (1 << output->crtc->pipe)))
continue;
/* Does the writeback connector support the output gbm format? */
if (!weston_drm_format_array_find_format(&wb->formats,
output->format->format))
continue;
return wb;
}
return NULL;
}
static struct drm_writeback_state *
drm_writeback_state_alloc(void)
{
struct drm_writeback_state *state;
state = zalloc(sizeof *state);
if (!state)
return NULL;
state->state = DRM_OUTPUT_WB_SCREENSHOT_OFF;
state->out_fence_fd = -1;
wl_array_init(&state->referenced_fbs);
return state;
}
static void
drm_writeback_state_free(struct drm_writeback_state *state)
{
struct drm_fb **fb;
if (state->out_fence_fd >= 0)
close(state->out_fence_fd);
/* Unref framebuffer that was given to save the content of the writeback */
if (state->fb)
drm_fb_unref(state->fb);
/* Unref framebuffers that were in use in the same commit of the one with
* the writeback setup */
wl_array_for_each(fb, &state->referenced_fbs)
drm_fb_unref(*fb);
wl_array_release(&state->referenced_fbs);
free(state);
}
static void
drm_output_pick_writeback_capture_task(struct drm_output *output)
{
struct weston_capture_task *ct;
struct weston_buffer *buffer;
struct drm_writeback *wb;
const char *msg;
int32_t width = output->base.current_mode->width;
int32_t height = output->base.current_mode->height;
uint32_t format = output->format->format;
assert(output->device->atomic_modeset);
ct = weston_output_pull_capture_task(&output->base,
WESTON_OUTPUT_CAPTURE_SOURCE_WRITEBACK,
width, height, pixel_format_get_info(format));
if (!ct)
return;
if (output->base.disable_planes > 0) {
msg = "drm: KMS planes usage is disabled for now, so " \
"writeback capture tasks are rejected";
goto err;
}
wb = drm_output_find_compatible_writeback(output);
if (!wb) {
msg = "drm: could not find writeback connector for output";
goto err;
}
buffer = weston_capture_task_get_buffer(ct);
assert(buffer->width == width);
assert(buffer->height == height);
assert(buffer->pixel_format->format == output->format->format);
output->wb_state = drm_writeback_state_alloc();
if (!output->wb_state) {
msg = "drm: failed to allocate memory for writeback state";
goto err;
}
output->wb_state->fb = drm_fb_create_dumb(output->device, width, height, format);
if (!output->wb_state->fb) {
msg = "drm: failed to create dumb buffer for writeback state";
goto err_fb;
}
output->wb_state->output = output;
output->wb_state->wb = wb;
output->wb_state->state = DRM_OUTPUT_WB_SCREENSHOT_PREPARE_COMMIT;
output->wb_state->ct = ct;
return;
err_fb:
drm_writeback_state_free(output->wb_state);
output->wb_state = NULL;
err:
weston_capture_task_retire_failed(ct, msg);
}
#ifdef BUILD_DRM_GBM
/**
* Update the image for the current cursor surface
*
* @param plane_state DRM cursor plane state
* @param ev Source view for cursor
*/
static void
cursor_bo_update(struct drm_output *output, struct weston_view *ev)
{
struct drm_device *device = output->device;
struct gbm_bo *bo = output->gbm_cursor_fb[output->current_cursor]->bo;
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
uint32_t buf[device->cursor_width * device->cursor_height];
int32_t stride;
uint8_t *s;
int i;
assert(buffer && buffer->shm_buffer);
assert(buffer->width <= device->cursor_width);
assert(buffer->height <= device->cursor_height);
memset(buf, 0, sizeof buf);
stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
s = wl_shm_buffer_get_data(buffer->shm_buffer);
wl_shm_buffer_begin_access(buffer->shm_buffer);
for (i = 0; i < buffer->height; i++)
memcpy(buf + i * device->cursor_width,
s + i * stride,
buffer->width * 4);
wl_shm_buffer_end_access(buffer->shm_buffer);
if (bo) {
if (gbm_bo_write(bo, buf, sizeof buf) < 0)
weston_log("failed update cursor: %s\n", strerror(errno));
} else {
memcpy(output->gbm_cursor_fb[output->current_cursor]->map,
buf, sizeof buf);
}
}
#else
static void
cursor_bo_update(struct drm_output *output, struct weston_view *ev)
{
}
#endif
static int
drm_output_repaint(struct weston_output *output_base)
2013-05-01 20:52:12 +00:00
{
struct drm_output *output = to_drm_output(output_base);
struct drm_output_state *state = NULL;
struct drm_plane_state *scanout_state;
struct drm_plane_state *cursor_state;
struct drm_pending_state *pending_state;
struct drm_device *device;
2013-05-01 20:52:12 +00:00
assert(output);
assert(!output->virtual);
device = output->device;
pending_state = device->repaint_data;
if (output->disable_pending || output->destroy_pending)
goto err;
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);
state->dpms = WESTON_DPMS_ON;
cursor_state = drm_output_state_get_existing_plane(state,
output->cursor_plane);
if (cursor_state && cursor_state->fb) {
pixman_region32_t damage;
assert(cursor_state->plane == output->cursor_plane);
assert(cursor_state->fb == output->gbm_cursor_fb[0]);
pixman_region32_init(&damage);
weston_output_flush_damage_for_plane(&output->base,
&output->cursor_plane->base,
&damage);
if (pixman_region32_not_empty(&damage)) {
output->current_cursor++;
output->current_cursor =
output->current_cursor %
ARRAY_LENGTH(output->gbm_cursor_fb);
cursor_bo_update(output, output->cursor_view);
}
pixman_region32_fini(&damage);
cursor_state->fb = drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
drm_fb_unref(output->gbm_cursor_fb[0]);
}
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
if (output_base->allow_protection)
state->protection = output_base->desired_protection;
else
state->protection = WESTON_HDCP_DISABLE;
if (drm_output_ensure_hdr_output_metadata_blob(output) < 0)
goto err;
if (device->atomic_modeset)
drm_output_pick_writeback_capture_task(output);
drm_output_render(state);
scanout_state = drm_output_state_get_plane(state,
output->scanout_plane);
if (!scanout_state || !scanout_state->fb)
goto err;
return 0;
2013-05-01 20:52:12 +00:00
err:
drm_output_state_free(state);
return -1;
2013-05-01 20:52:12 +00:00
}
/* Determine the type of vblank synchronization to use for the output.
*
* The pipe parameter indicates which CRTC is in use. Knowing this, we
* can determine which vblank sequence type to use for it. Traditional
* cards had only two CRTCs, with CRTC 0 using no special flags, and
* CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
* parameter indicates this.
*
* Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
* 0-31. If this is non-zero it indicates we're dealing with a
* multi-gpu situation and we need to calculate the vblank sync
* using DRM_BLANK_HIGH_CRTC_MASK.
*/
static unsigned int
drm_waitvblank_pipe(struct drm_crtc *crtc)
{
if (crtc->pipe > 1)
return (crtc->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
DRM_VBLANK_HIGH_CRTC_MASK;
else if (crtc->pipe > 0)
return DRM_VBLANK_SECONDARY;
else
return 0;
}
static int
drm_output_start_repaint_loop(struct weston_output *output_base)
{
struct drm_output *output = to_drm_output(output_base);
struct drm_pending_state *pending_state;
struct drm_plane *scanout_plane = output->scanout_plane;
struct drm_device *device = output->device;
struct drm_backend *backend = device->backend;
struct weston_compositor *compositor = backend->compositor;
struct timespec ts, tnow;
struct timespec vbl2now;
int64_t refresh_nsec;
uint32_t flags = WP_PRESENTATION_FEEDBACK_INVALID;
int ret;
drmVBlank vbl = {
.request.type = DRM_VBLANK_RELATIVE,
.request.sequence = 0,
.request.signal = 0,
};
if (output->disable_pending || output->destroy_pending)
return 0;
if (!scanout_plane->state_cur->fb) {
/* We can't page flip if there's no mode set */
goto finish_frame;
}
/* Need to smash all state in from scratch; current timings might not
* be what we want, page flip might not work, etc.
*/
if (device->state_invalid)
goto finish_frame;
assert(scanout_plane->state_cur->output == output);
/* If we're tearing, we've been generating timestamps from the
* presentation clock that don't line up with the msc timestamps,
* and could be more recent than the latest msc, which would cause
* an assert() later.
*/
if (output->state_cur->tear) {
flags |= WESTON_FINISH_FRAME_TEARING;
goto finish_frame;
}
/* Try to get current msc and timestamp via instant query */
vbl.request.type |= drm_waitvblank_pipe(output->crtc);
ret = drmWaitVBlank(device->drm.fd, &vbl);
/* Error ret or zero timestamp means failure to get valid timestamp */
if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
ts.tv_sec = vbl.reply.tval_sec;
ts.tv_nsec = vbl.reply.tval_usec * 1000;
/* Valid timestamp for most recent vblank - not stale?
* Stale ts could happen on Linux 3.17+, so make sure it
* is not older than 1 refresh duration since now.
*/
weston_compositor_read_presentation_clock(compositor,
&tnow);
timespec_sub(&vbl2now, &tnow, &ts);
refresh_nsec =
millihz_to_nsec(output->base.current_mode->refresh);
if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
drm_output_update_msc(output, vbl.reply.sequence);
weston_output_finish_frame(output_base, &ts, flags);
return 0;
}
}
/* Immediate query didn't provide valid timestamp.
* Use pageflip fallback.
*/
assert(!output->page_flip_pending);
assert(!output->state_last);
pending_state = drm_pending_state_alloc(device);
drm_output_state_duplicate(output->state_cur, pending_state,
DRM_OUTPUT_STATE_PRESERVE_PLANES);
ret = drm_pending_state_apply(pending_state);
if (ret != 0) {
weston_log("applying repaint-start state failed: %s\n",
strerror(errno));
if (ret == -EACCES || ret == -EBUSY)
return ret;
goto finish_frame;
}
return 0;
finish_frame:
/* if we cannot page-flip, immediately finish frame */
weston_output_finish_frame(output_base, NULL, flags);
return 0;
}
/**
* Begin a new repaint cycle
*
* Called by the core compositor at the beginning of a repaint cycle. Creates
* a new pending_state structure to own any output state created by individual
* output repaint functions until the repaint is flushed or cancelled.
*/
static void
drm_repaint_begin(struct weston_backend *backend)
{
struct drm_backend *b = container_of(backend, struct drm_backend, base);
struct drm_device *device;
struct drm_pending_state *pending_state;
device = b->drm;
pending_state = drm_pending_state_alloc(device);
device->repaint_data = pending_state;
if (weston_log_scope_is_enabled(b->debug)) {
char *dbg = weston_compositor_print_scene_graph(b->compositor);
drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
device->repaint_data);
drm_debug(b, "%s", dbg);
free(dbg);
}
wl_list_for_each(device, &b->kms_list, link) {
pending_state = drm_pending_state_alloc(device);
device->repaint_data = pending_state;
if (weston_log_scope_is_enabled(b->debug)) {
char *dbg = weston_compositor_print_scene_graph(b->compositor);
drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
pending_state);
drm_debug(b, "%s", dbg);
free(dbg);
}
}
}
/**
* Flush a repaint set
*
* Called by the core compositor when a repaint cycle has been completed
* and should be flushed. Frees the pending state, transitioning ownership
* of the output state from the pending state, to the update itself. When
* the update completes (see drm_output_update_complete), the output
* state will be freed.
*/
static int
drm_repaint_flush(struct weston_backend *backend)
{
struct drm_backend *b = container_of(backend, struct drm_backend, base);
struct drm_device *device;
struct drm_pending_state *pending_state;
int ret;
device = b->drm;
pending_state = device->repaint_data;
ret = drm_pending_state_apply(pending_state);
if (ret != 0)
weston_log("repaint-flush failed: %s\n", strerror(errno));
drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
device->repaint_data = NULL;
wl_list_for_each(device, &b->kms_list, link) {
pending_state = device->repaint_data;
ret = drm_pending_state_apply(pending_state);
if (ret != 0)
weston_log("repaint-flush failed: %s\n", strerror(errno));
drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
device->repaint_data = NULL;
}
return (ret == -EACCES || ret == -EBUSY) ? ret : 0;
}
/**
* Cancel a repaint set
*
* Called by the core compositor when a repaint has finished, so the data
* held across the repaint cycle should be discarded.
*/
static void
drm_repaint_cancel(struct weston_backend *backend)
{
struct drm_backend *b = container_of(backend, struct drm_backend, base);
struct drm_device *device;
struct drm_pending_state *pending_state;
device = b->drm;
pending_state = device->repaint_data;
drm_pending_state_free(pending_state);
drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
device->repaint_data = NULL;
wl_list_for_each(device, &b->kms_list, link) {
pending_state = device->repaint_data;
drm_pending_state_free(pending_state);
drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
device->repaint_data = NULL;
}
}
static int
drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
static void
drm_output_fini_pixman(struct drm_output *output);
static int
drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
{
struct drm_output *output = to_drm_output(output_base);
struct drm_mode *drm_mode;
assert(output);
drm_mode = drm_output_choose_mode(output, mode);
if (!drm_mode) {
weston_log("%s: invalid resolution %dx%d\n",
output_base->name, mode->width, mode->height);
return -1;
}
if (&drm_mode->base == output->base.current_mode)
return 0;
output->base.current_mode->flags = 0;
output->base.current_mode = &drm_mode->base;
output->base.current_mode->flags =
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
if (output->page_flip_pending || output->atomic_complete_pending) {
output->mode_switch_pending = true;
return 0;
}
return drm_output_apply_mode(output);
}
static int
drm_output_apply_mode(struct drm_output *output)
{
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct weston_size fb_size;
compositor-drm: Introduce fb_last member Previously, framebuffers were stored as fb_current and fb_pending. In this scheme, current was the last buffer that the kernel/hardware had acknowledged displaying: a framebuffer would be created, set as fb_pending, and Weston would request the kernel display it. When the kernel signals that the request was completed and the hardware had made the buffer current (i.e. page_flip_handler / vblank_handler), we would unreference the old fb_current, and promote fb_pending to fb_current. In other words, the view is 'which buffer has turned to light?'. This patch changes them to a tristate of fb_last, fb_current and fb_pending, based around the kernel's view of the current state. fb_pending is used purely as a staging area for request construction; when the kernel acknowledges a request (e.g. drmModePageFlip returns 0), the previous buffer is moved to fb_last, and this new buffer to fb_current. When the kernel signals that the request has completed and the hardware has made the buffer current, we simply unreference and clear fb_last, without touching fb_current/fb_pending. The view here is now 'which state is current in the kernel?'. As all state changes are incremental on the last state submitted to the kernel, even if the hardware has not yet been able to make it current, this simplifies state tracking: all state submissions will always be relative to fb_current, rather than the previous (fb_pending) ? fb_pending : fb_current. The use of fb_pending is strictly bounded between a repaint cycle (including a grouped set of repaints) beginning, and those repaints being flushed to the kernel. fb_current will always be valid between an output's first repaint flush, and when a disable/destroy request has been processed. For a plane, it will be valid when a repaint cycle enabling that plane has been flushed, and when a repaint cycle disabling that plane has been flushed. fb_last is only present when a repaint request for the output/plane has been submitted, but not yet completed by the hardware. This is the same set of constructs which will be used for storing plane/output state objects in future patches. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2017-04-04 16:54:31 +00:00
/* XXX: This drops our current buffer too early, before we've started
* displaying it. Ideally this should be much more atomic and
* integrated with a full repaint cycle, rather than doing a
* sledgehammer modeswitch first, and only later showing new
* content.
*/
device->state_invalid = true;
fb_size.width = output->base.current_mode->width;
fb_size.height = output->base.current_mode->height;
weston_renderer_resize_output(&output->base, &fb_size, NULL);
if (b->compositor->renderer->type == WESTON_RENDERER_PIXMAN) {
drm_output_fini_pixman(output);
if (drm_output_init_pixman(output, b) < 0) {
weston_log("failed to init output pixman state with "
"new mode\n");
return -1;
}
} else {
drm_output_fini_egl(output);
if (drm_output_init_egl(output, b) < 0) {
weston_log("failed to init output egl state with "
"new mode");
return -1;
}
}
if (device->atomic_modeset)
weston_output_update_capture_info(&output->base,
WESTON_OUTPUT_CAPTURE_SOURCE_WRITEBACK,
output->base.current_mode->width,
output->base.current_mode->height,
pixel_format_get_info(output->format->format));
return 0;
}
static int
init_pixman(struct drm_backend *b)
{
return weston_compositor_init_renderer(b->compositor,
WESTON_RENDERER_PIXMAN, NULL);
}
/**
* Create a drm_plane for a hardware plane
*
* Creates one drm_plane structure for a hardware plane, and initialises its
* properties and formats.
*
* This function does not add the plane to the list of usable planes in Weston
* itself; the caller is responsible for this.
*
* Call drm_plane_destroy to clean up the plane.
*
* @sa drm_output_find_special_plane
* @param device DRM device
* @param kplane DRM plane to create
*/
static struct drm_plane *
drm_plane_create(struct drm_device *device, const drmModePlane *kplane)
{
struct drm_backend *b = device->backend;
struct weston_compositor *compositor = b->compositor;
struct drm_plane *plane, *tmp;
drmModeObjectProperties *props;
uint64_t *zpos_range_values;
uint64_t *alpha_range_values;
plane = zalloc(sizeof(*plane));
if (!plane) {
weston_log("%s: out of memory\n", __func__);
return NULL;
}
plane->device = device;
plane->state_cur = drm_plane_state_alloc(NULL, plane);
plane->state_cur->complete = true;
plane->possible_crtcs = kplane->possible_crtcs;
plane->plane_id = kplane->plane_id;
plane->crtc_id = kplane->crtc_id;
weston_drm_format_array_init(&plane->formats);
props = drmModeObjectGetProperties(device->drm.fd, kplane->plane_id,
DRM_MODE_OBJECT_PLANE);
if (!props) {
weston_log("couldn't get plane properties\n");
goto err;
}
drm_property_info_populate(device, plane_props, plane->props,
WDRM_PLANE__COUNT, props);
plane->type =
drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
props,
WDRM_PLANE_TYPE__COUNT);
zpos_range_values =
drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS],
props);
if (zpos_range_values) {
plane->zpos_min = zpos_range_values[0];
plane->zpos_max = zpos_range_values[1];
} else {
plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
}
alpha_range_values =
drm_property_get_range_values(&plane->props[WDRM_PLANE_ALPHA],
props);
if (alpha_range_values) {
plane->alpha_min = (uint16_t) alpha_range_values[0];
plane->alpha_max = (uint16_t) alpha_range_values[1];
} else {
plane->alpha_min = DRM_PLANE_ALPHA_OPAQUE;
plane->alpha_max = DRM_PLANE_ALPHA_OPAQUE;
}
if (drm_plane_populate_formats(plane, kplane, props,
device->fb_modifiers) < 0) {
drmModeFreeObjectProperties(props);
goto err;
}
drmModeFreeObjectProperties(props);
if (plane->type == WDRM_PLANE_TYPE__COUNT)
goto err_props;
weston_plane_init(&plane->base, compositor);
wl_list_for_each(tmp, &device->plane_list, link) {
if (tmp->zpos_max < plane->zpos_max) {
wl_list_insert(tmp->link.prev, &plane->link);
break;
}
}
if (plane->link.next == NULL)
wl_list_insert(device->plane_list.prev, &plane->link);
return plane;
err_props:
drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
err:
weston_drm_format_array_fini(&plane->formats);
drm_plane_state_free(plane->state_cur, true);
free(plane);
return NULL;
}
/**
* Find, or create, a special-purpose plane
*
* @param device DRM device
* @param output Output to use for plane
* @param type Type of plane
*/
static struct drm_plane *
drm_output_find_special_plane(struct drm_device *device,
struct drm_output *output,
enum wdrm_plane_type type)
{
struct drm_backend *b = device->backend;
struct drm_plane *plane;
wl_list_for_each(plane, &device->plane_list, link) {
struct weston_output *base;
bool found_elsewhere = false;
if (plane->type != type)
continue;
if (!drm_plane_is_available(plane, output))
continue;
/* On some platforms, primary/cursor planes can roam
* between different CRTCs, so make sure we don't claim the
* same plane for two outputs. */
wl_list_for_each(base, &b->compositor->output_list, link) {
struct drm_output *tmp = to_drm_output(base);
if (!tmp)
continue;
if (tmp->cursor_plane == plane ||
tmp->scanout_plane == plane) {
found_elsewhere = true;
break;
}
}
if (found_elsewhere)
continue;
/* If a plane already has a CRTC selected and it is not our
* output's CRTC, then do not select this plane. We cannot
* switch away a plane from a CTRC when active. */
if ((type == WDRM_PLANE_TYPE_PRIMARY) &&
(plane->crtc_id != 0) &&
(plane->crtc_id != output->crtc->crtc_id))
continue;
plane->possible_crtcs = (1 << output->crtc->pipe);
return plane;
}
return NULL;
}
/**
* Destroy one DRM plane
*
* Destroy a DRM plane, removing it from screen and releasing its retained
* buffers in the process. The counterpart to drm_plane_create.
*
* @param plane Plane to deallocate (will be freed)
*/
static void
drm_plane_destroy(struct drm_plane *plane)
{
struct drm_device *device = plane->device;
if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
drmModeSetPlane(device->drm.fd, plane->plane_id,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
drm_plane_state_free(plane->state_cur, true);
drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
weston_plane_release(&plane->base);
weston_drm_format_array_fini(&plane->formats);
wl_list_remove(&plane->link);
free(plane);
}
/**
* Initialise sprites (overlay planes)
*
* Walk the list of provided DRM planes, and add overlay planes.
*
* Call destroy_sprites to free these planes.
*
* @param device DRM device
*/
static void
create_sprites(struct drm_device *device)
{
struct drm_backend *b = device->backend;
drmModePlaneRes *kplane_res;
drmModePlane *kplane;
struct drm_plane *drm_plane;
uint32_t i;
uint32_t next_plane_idx = 0;
kplane_res = drmModeGetPlaneResources(device->drm.fd);
if (!kplane_res) {
weston_log("failed to get plane resources: %s\n",
strerror(errno));
return;
}
for (i = 0; i < kplane_res->count_planes; i++) {
kplane = drmModeGetPlane(device->drm.fd, kplane_res->planes[i]);
if (!kplane)
continue;
drm_plane = drm_plane_create(device, kplane);
drmModeFreePlane(kplane);
if (!drm_plane)
continue;
if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
weston_compositor_stack_plane(b->compositor,
&drm_plane->base,
NULL);
}
wl_list_for_each (drm_plane, &device->plane_list, link)
drm_plane->plane_idx = next_plane_idx++;
drmModeFreePlaneResources(kplane_res);
}
/**
* Clean up sprites (overlay planes)
*
* The counterpart to create_sprites.
*
* @param device DRM device
*/
static void
destroy_sprites(struct drm_device *device)
{
struct drm_plane *plane, *next;
wl_list_for_each_safe(plane, next, &device->plane_list, link)
drm_plane_destroy(plane);
}
/* returns a value between 0-255 range, where higher is brighter */
static uint32_t
drm_get_backlight(struct drm_head *head)
{
long brightness, max_brightness, norm;
brightness = backlight_get_brightness(head->backlight);
max_brightness = backlight_get_max_brightness(head->backlight);
/* convert it on a scale of 0 to 255 */
norm = (brightness * 255)/(max_brightness);
return (uint32_t) norm;
}
/* values accepted are between 0-255 range */
static void
drm_set_backlight(struct weston_output *output_base, uint32_t value)
{
struct drm_output *output = to_drm_output(output_base);
struct drm_head *head;
long max_brightness, new_brightness;
if (value > 255)
return;
wl_list_for_each(head, &output->base.head_list, base.output_link) {
if (!head->backlight)
return;
max_brightness = backlight_get_max_brightness(head->backlight);
/* get denormalized value */
new_brightness = (value * max_brightness) / 255;
backlight_set_brightness(head->backlight, new_brightness);
}
}
static void
drm_output_init_backlight(struct drm_output *output)
{
struct weston_head *base;
struct drm_head *head;
output->base.set_backlight = NULL;
wl_list_for_each(base, &output->base.head_list, output_link) {
head = to_drm_head(base);
if (head->backlight) {
weston_log("Initialized backlight for head '%s', device %s\n",
head->base.name, head->backlight->path);
if (!output->base.set_backlight) {
output->base.set_backlight = drm_set_backlight;
output->base.backlight_current =
drm_get_backlight(head);
}
}
}
}
/**
* Power output on or off
*
* The DPMS/power level of an output is used to switch it on or off. This
* is DRM's hook for doing so, which can called either as part of repaint,
* or independently of the repaint loop.
*
* If we are called as part of repaint, we simply set the relevant bit in
* state and return.
*
* This function is never called on a virtual output.
*/
static void
drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
{
struct drm_output *output = to_drm_output(output_base);
struct drm_device *device = output->device;
struct drm_pending_state *pending_state = device->repaint_data;
struct drm_output_state *state;
int ret;
assert(output);
assert(!output->virtual);
if (output->state_cur->dpms == level)
return;
/* If we're being called during the repaint loop, then this is
* simple: discard any previously-generated state, and create a new
* state where we disable everything. When we come to flush, this
* will be applied.
*
* However, we need to be careful: we can be called whilst another
* output is in its repaint cycle (pending_state exists), but our
* output still has an incomplete state application outstanding.
* In that case, we need to wait until that completes. */
if (pending_state && !output->state_last) {
/* The repaint loop already sets DPMS on; we don't need to
* explicitly set it on here, as it will already happen
* whilst applying the repaint state. */
if (level == WESTON_DPMS_ON)
return;
state = drm_pending_state_get_output(pending_state, output);
if (state)
drm_output_state_free(state);
state = drm_output_get_disable_state(pending_state, output);
return;
}
/* As we throw everything away when disabling, just send us back through
* a repaint cycle. */
if (level == WESTON_DPMS_ON) {
if (output->dpms_off_pending)
output->dpms_off_pending = false;
weston_output_schedule_repaint(output_base);
return;
}
/* If we've already got a request in the pipeline, then we need to
* park our DPMS request until that request has quiesced. */
if (output->state_last) {
output->dpms_off_pending = true;
return;
}
pending_state = drm_pending_state_alloc(device);
drm_output_get_disable_state(pending_state, output);
ret = drm_pending_state_apply_sync(pending_state);
if (ret != 0)
weston_log("drm_set_dpms: couldn't disable output?\n");
}
static const char * const connector_type_names[] = {
[DRM_MODE_CONNECTOR_Unknown] = "Unknown",
[DRM_MODE_CONNECTOR_VGA] = "VGA",
[DRM_MODE_CONNECTOR_DVII] = "DVI-I",
[DRM_MODE_CONNECTOR_DVID] = "DVI-D",
[DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
[DRM_MODE_CONNECTOR_Composite] = "Composite",
[DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
[DRM_MODE_CONNECTOR_LVDS] = "LVDS",
[DRM_MODE_CONNECTOR_Component] = "Component",
[DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
[DRM_MODE_CONNECTOR_DisplayPort] = "DP",
[DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
[DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
[DRM_MODE_CONNECTOR_TV] = "TV",
[DRM_MODE_CONNECTOR_eDP] = "eDP",
[DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
[DRM_MODE_CONNECTOR_DSI] = "DSI",
[DRM_MODE_CONNECTOR_DPI] = "DPI",
};
/** Create a name given a DRM connector
*
* \param con The DRM connector whose type and id form the name.
* \return A newly allocate string, or NULL on error. Must be free()'d
* after use.
*
* The name does not identify the DRM display device.
*/
static char *
make_connector_name(const drmModeConnector *con)
{
char *name;
const char *type_name = NULL;
int ret;
if (con->connector_type < ARRAY_LENGTH(connector_type_names))
type_name = connector_type_names[con->connector_type];
if (!type_name)
type_name = "UNNAMED";
ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
if (ret < 0)
return NULL;
return name;
}
static int
drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
{
struct weston_renderer *renderer = output->base.compositor->renderer;
const struct pixman_renderer_interface *pixman = renderer->pixman;
struct drm_device *device = output->device;
int w = output->base.current_mode->width;
int h = output->base.current_mode->height;
unsigned int i;
const struct pixman_renderer_output_options options = {
.use_shadow = b->use_pixman_shadow,
.fb_size = { .width = w, .height = h },
.format = output->format
};
assert(options.format);
if (!options.format->pixman_format) {
weston_log("Unsupported pixel format %s\n",
options.format->drm_format_name);
return -1;
}
if (pixman->output_create(&output->base, &options) < 0)
goto err;
/* FIXME error checking */
for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
output->dumb[i] = drm_fb_create_dumb(device, w, h,
options.format->format);
if (!output->dumb[i])
goto err;
output->renderbuffer[i] =
pixman->create_image_from_ptr(&output->base,
options.format, w, h,
output->dumb[i]->map,
output->dumb[i]->strides[0]);
if (!output->renderbuffer[i])
goto err;
pixman_region32_init_rect(&output->renderbuffer[i]->damage,
output->base.pos.c.x,
output->base.pos.c.y,
output->base.width,
output->base.height);
}
compositor-drm: Add aspect-ratio parsing support The flag bits 19-22 of the connector modes, provide the aspect-ratio information. This information can be stored in flags bits of the weston mode structure, so that it can used for setting a mode with a particular aspect-ratio. Currently, DRM layer supports aspect-ratio with atomic-modesetting by default. For legacy modeset path, the user-space needs to set the drm client cap for aspect-ratio, if it wants aspect-ratio information in modes. This patch: - preserves aspect-ratio flags from kernel video modes and accommodates it in wayland mode. - uses aspect-ratio to pick the appropriate mode during modeset. - changes the mode format in configuration file weston.ini to accommodate aspect-ratio information as: WIDTHxHEIGHT@REFRESH-RATE ASPECT-RATIO The aspect-ratio can take the following values : 4:3, 16:9, 64:27, 256:135. v2: As per recommendation from Pekka Paalanen, Quentin Glidic, Daniel Stone, dropped the aspect-ratio info from wayland protocol, thereby avoiding exposure of aspect-ratio to the client. v3: As suggested by Pekka Paalanen, added aspect_ratio field to store aspect-ratio information from the drm. Also added drm client capability for aspect-ratio, as recommended by Daniel Vetter. v4: Minor modifications and fixes as suggested by Pekka Paalanen. v5: Rebased, fixed some styling issues, and added aspect-ratio information while printing weston_modes. v6: Moved the man pages changes to a different patch. Minor reorganization of code as suggested by Pekka Paalanen. Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com> [Pekka: replace ARRAY_SIZE with ARRAY_LENGTH] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2097-03-18 18:54:57 +00:00
weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
b->use_pixman_shadow ? "uses" : "does not use");
return 0;
err:
for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
if (output->dumb[i])
drm_fb_unref(output->dumb[i]);
if (output->renderbuffer[i])
weston_renderbuffer_unref(output->renderbuffer[i]);
output->dumb[i] = NULL;
output->renderbuffer[i] = NULL;
}
pixman->output_destroy(&output->base);
return -1;
}
static void
drm_output_fini_pixman(struct drm_output *output)
{
struct weston_renderer *renderer = output->base.compositor->renderer;
struct drm_backend *b = output->backend;
unsigned int i;
/* Destroying the Pixman surface will destroy all our buffers,
* regardless of refcount. Ensure we destroy them here. */
if (!b->compositor->shutting_down &&
output->scanout_plane->state_cur->fb &&
output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
drm_plane_reset_state(output->scanout_plane);
}
for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
weston_renderbuffer_unref(output->renderbuffer[i]);
drm_fb_unref(output->dumb[i]);
output->dumb[i] = NULL;
output->renderbuffer[i] = NULL;
}
renderer->pixman->output_destroy(&output->base);
}
static void
setup_output_seat_constraint(struct drm_backend *b,
struct weston_output *output,
const char *s)
{
if (strcmp(s, "") != 0) {
struct weston_pointer *pointer;
struct udev_seat *seat;
seat = udev_seat_get_named(&b->input, s);
if (!seat)
return;
seat->base.output = output;
pointer = weston_seat_get_pointer(&seat->base);
if (pointer)
pointer->pos = weston_pointer_clamp(pointer,
pointer->pos);
}
}
static int
drm_output_attach_head(struct weston_output *output_base,
struct weston_head *head_base)
{
struct drm_output *output = to_drm_output(output_base);
struct drm_backend *b = output->backend;
struct drm_device *device = b->drm;
struct drm_head *head = to_drm_head(head_base);
if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
return -1;
wl_list_remove(&head->disable_head_link);
wl_list_init(&head->disable_head_link);
if (!output_base->enabled)
return 0;
/* XXX: ensure the configuration will work.
* This is actually impossible without major infrastructure
* work. */
/* Need to go through modeset to add connectors. */
/* XXX: Ideally we'd do this per-output, not globally. */
/* XXX: Doing it globally, what guarantees another output's update
* will not clear the flag before this output is updated?
*/
device->state_invalid = true;
weston_output_schedule_repaint(output_base);
return 0;
}
static void
drm_output_detach_head(struct weston_output *output_base,
struct weston_head *head_base)
{
struct drm_output *output = to_drm_output(output_base);
struct drm_head *head = to_drm_head(head_base);
if (!output_base->enabled)
return;
/* Drop connectors that should no longer be driven on next repaint. */
wl_list_insert(&output->disable_head, &head->disable_head_link);
}
int
parse_gbm_format(const char *s, const struct pixel_format_info *default_format,
const struct pixel_format_info **format)
{
if (s == NULL) {
*format = default_format;
return 0;
}
/* GBM formats and DRM formats are identical. */
*format = pixel_format_get_info_by_drm_name(s);
if (!*format) {
weston_log("fatal: unrecognized pixel format: %s\n", s);
return -1;
}
return 0;
}
static int
drm_head_read_current_setup(struct drm_head *head, struct drm_device *device)
{
int drm_fd = device->drm.fd;
drmModeConnector *conn = head->connector.conn;
drmModeEncoder *encoder;
drmModeCrtc *crtc;
/* Get the current mode on the crtc that's currently driving
* this connector. */
encoder = drmModeGetEncoder(drm_fd, conn->encoder_id);
if (encoder != NULL) {
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
head->inherited_crtc_id = encoder->crtc_id;
crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
drmModeFreeEncoder(encoder);
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
if (crtc == NULL)
return -1;
if (crtc->mode_valid)
head->inherited_mode = crtc->mode;
drmModeFreeCrtc(crtc);
}
/* Get the current max_bpc that's currently configured to
* this connector. */
head->inherited_max_bpc = drm_property_get_value(
&head->connector.props[WDRM_CONNECTOR_MAX_BPC],
head->connector.props_drm, 0);
return 0;
}
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
static void
drm_output_set_gbm_format(struct weston_output *base,
const char *gbm_format)
{
struct drm_output *output = to_drm_output(base);
if (parse_gbm_format(gbm_format, NULL, &output->format) == -1)
output->format = NULL;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
}
static void
drm_output_set_seat(struct weston_output *base,
const char *seat)
{
struct drm_output *output = to_drm_output(base);
struct drm_backend *b = output->backend;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
setup_output_seat_constraint(b, &output->base,
seat ? seat : "");
}
static void
drm_output_set_max_bpc(struct weston_output *base, unsigned max_bpc)
{
struct drm_output *output = to_drm_output(base);
assert(output);
assert(!output->base.enabled);
output->max_bpc = max_bpc;
}
static const struct { const char *name; uint32_t token; } content_types[] = {
{ "no data", WDRM_CONTENT_TYPE_NO_DATA },
{ "graphics", WDRM_CONTENT_TYPE_GRAPHICS },
{ "photo", WDRM_CONTENT_TYPE_PHOTO },
{ "cinema", WDRM_CONTENT_TYPE_CINEMA },
{ "game", WDRM_CONTENT_TYPE_GAME },
};
static int
drm_output_set_content_type(struct weston_output *base,
const char *content_type)
{
unsigned int i;
struct drm_output *output = to_drm_output(base);
if (content_type == NULL) {
output->content_type = WDRM_CONTENT_TYPE_NO_DATA;
return 0;
}
for (i = 0; i < ARRAY_LENGTH(content_types); i++)
if (strcmp(content_types[i].name, content_type) == 0) {
output->content_type = content_types[i].token;
return 0;
}
weston_log("Error: unknown content-type for output %s: \"%s\"\n",
base->name, content_type);
output->content_type = WDRM_CONTENT_TYPE_NO_DATA;
return -1;
}
static int
drm_output_init_gamma_size(struct drm_output *output)
{
struct drm_device *device = output->device;
drmModeCrtc *crtc;
assert(output->base.compositor);
assert(output->crtc);
crtc = drmModeGetCrtc(device->drm.fd, output->crtc->crtc_id);
if (!crtc)
return -1;
output->base.gamma_size = crtc->gamma_size;
drmModeFreeCrtc(crtc);
return 0;
}
enum writeback_screenshot_state
drm_output_get_writeback_state(struct drm_output *output)
{
if (!output->wb_state)
return DRM_OUTPUT_WB_SCREENSHOT_OFF;
return output->wb_state->state;
}
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
/** Pick a CRTC that might be able to drive all attached connectors
*
* @param output The output whose attached heads to include.
* @return CRTC object to pick, or NULL on failure or not found.
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
*/
static struct drm_crtc *
drm_output_pick_crtc(struct drm_output *output)
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
{
struct drm_device *device = output->device;
struct drm_backend *backend = device->backend;
struct weston_compositor *compositor = backend->compositor;
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
struct weston_head *base;
struct drm_head *head;
struct drm_crtc *crtc;
struct drm_crtc *best_crtc = NULL;
struct drm_crtc *fallback_crtc = NULL;
struct drm_crtc *existing_crtc[32];
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
uint32_t possible_crtcs = 0xffffffff;
unsigned n = 0;
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
uint32_t crtc_id;
unsigned int i;
bool match;
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
/* This algorithm ignores drmModeEncoder::possible_clones restriction,
* because it is more often set wrong than not in the kernel. */
/* Accumulate a mask of possible crtcs and find existing routings. */
wl_list_for_each(base, &output->base.head_list, output_link) {
head = to_drm_head(base);
possible_crtcs &=
drm_connector_get_possible_crtcs_mask(&head->connector);
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
crtc_id = head->inherited_crtc_id;
if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
existing_crtc[n++] = drm_crtc_find(device, crtc_id);
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
}
/* Find a crtc that could drive each connector individually at least,
* and prefer existing routings. */
wl_list_for_each(crtc, &device->crtc_list, link) {
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
/* Could the crtc not drive each connector? */
if (!(possible_crtcs & (1 << crtc->pipe)))
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
continue;
/* Is the crtc already in use? */
if (crtc->output)
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
continue;
/* Try to preserve the existing CRTC -> connector routing;
* it makes initialisation faster, and also since we have a
* very dumb picking algorithm, may preserve a better
* choice. */
for (i = 0; i < n; i++) {
if (existing_crtc[i] == crtc)
return crtc;
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
}
/* Check if any other head had existing routing to this CRTC.
* If they did, this is not the best CRTC as it might be needed
* for another output we haven't enabled yet. */
match = false;
wl_list_for_each(base, &compositor->head_list, compositor_link) {
head = to_drm_head(base);
if (!head)
continue;
if (head->base.output == &output->base)
continue;
if (weston_head_is_enabled(&head->base))
continue;
if (head->inherited_crtc_id == crtc->crtc_id) {
match = true;
break;
}
}
if (!match)
best_crtc = crtc;
fallback_crtc = crtc;
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
}
if (best_crtc)
return best_crtc;
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
if (fallback_crtc)
return fallback_crtc;
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
/* Likely possible_crtcs was empty due to asking for clones,
* but since the DRM documentation says the kernel lies, let's
* pick one crtc anyway. Trial and error is the only way to
* be sure if something doesn't work. */
/* First pick any existing assignment. */
for (i = 0; i < n; i++) {
crtc = existing_crtc[i];
if (!crtc->output)
return crtc;
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
}
/* Otherwise pick any available crtc. */
wl_list_for_each(crtc, &device->crtc_list, link) {
if (!crtc->output)
return crtc;
}
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
return NULL;
}
/** Create an "empty" drm_crtc. It will only set its ID, pipe and props. After
* all, it adds the object to the DRM-backend CRTC list.
*/
static struct drm_crtc *
drm_crtc_create(struct drm_device *device, uint32_t crtc_id, uint32_t pipe)
{
struct drm_crtc *crtc;
drmModeObjectPropertiesPtr props;
props = drmModeObjectGetProperties(device->drm.fd, crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!props) {
weston_log("failed to get CRTC properties\n");
return NULL;
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
}
crtc = zalloc(sizeof(*crtc));
if (!crtc)
goto ret;
drm_property_info_populate(device, crtc_props, crtc->props_crtc,
WDRM_CRTC__COUNT, props);
crtc->device = device;
crtc->crtc_id = crtc_id;
crtc->pipe = pipe;
crtc->output = NULL;
/* Add it to the last position of the DRM-backend CRTC list */
wl_list_insert(device->crtc_list.prev, &crtc->link);
ret:
drmModeFreeObjectProperties(props);
return crtc;
compositor-drm: rewrite crtc picking for clone mode To support shared-CRTC clone mode, the chosen CRTC needs to support driving all the attached connectors. Replace the old algorithm with a new one that takes into account all associated connectors. Ideally it should use possible_clones mask to check which encoders (and therefore connectors) actually can be in a cloned set. However, the DRM documentation says about possible_clones and possible_crtcs masks both: "In reality almost every driver gets this wrong." - https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#c.drm_encoder Looking at a target device and its kernel where clone mode is desired, possible_clones is indeed self-conflicting and would not allow cloning at all. Therefore the implemented algorithm replaces the checking of possible_clones with luck. It even goes out of its way to find any CRTC for a configuration, even if not advertised by the kernel as not supported. Libweston would need infrastructure to allow trial-and-error CRTC allocation: rather than picking one CRTC in advance and do or die, it should try all available CRTCs one by one. Unfortunately that is not yet possible, so this patch implements what it can. It is also the DRM upstream opinion that trial-and-error with ATOMIC_TEST would be the way to go. Unlike the old algorithm, the new algorithm prefers routings that were in place when Weston started instead of when enabling an output. When you never temporarily disable an output, this makes no difference. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Acked-by: Derek Foreman <derekf@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2017-11-20 11:31:06 +00:00
}
/** Destroy a drm_crtc object that was created with drm_crtc_create(). It will
* also remove it from the DRM-backend CRTC list.
*/
static void
drm_crtc_destroy(struct drm_crtc *crtc)
{
assert(!crtc->output);
wl_list_remove(&crtc->link);
drm_property_info_free(crtc->props_crtc, WDRM_CRTC__COUNT);
free(crtc);
}
/** Find all CRTCs of the fd and create drm_crtc objects for them.
*
* The CRTCs are saved in a list of the drm_backend and will keep there until
* the fd gets closed.
*
* @param device The DRM device structure.
* @param resources The DRM resources, it is taken with drmModeGetResources
* @return 0 on success (at least one CRTC in the list), -1 on failure.
*/
static int
drm_backend_create_crtc_list(struct drm_device *device, drmModeRes *resources)
{
struct drm_crtc *crtc, *crtc_tmp;
int i;
/* Iterate through all CRTCs */
for (i = 0; i < resources->count_crtcs; i++) {
/* Let's create an object for the CRTC and add it to the list */
crtc = drm_crtc_create(device, resources->crtcs[i], i);
if (!crtc)
goto err;
}
return 0;
err:
wl_list_for_each_safe(crtc, crtc_tmp, &device->crtc_list, link)
drm_crtc_destroy(crtc);
return -1;
}
/** Populates scanout and cursor planes for the output. Also sets the topology
* of the planes by adding them to the plane stacking list.
*/
static int
drm_output_init_planes(struct drm_output *output)
{
struct drm_backend *b = output->backend;
struct drm_device *device = output->device;
output->scanout_plane =
drm_output_find_special_plane(device, output,
WDRM_PLANE_TYPE_PRIMARY);
if (!output->scanout_plane) {
weston_log("Failed to find primary plane for output %s\n",
output->base.name);
return -1;
}
weston_compositor_stack_plane(b->compositor,
&output->scanout_plane->base,
&output->base.primary_plane);
/* Failing to find a cursor plane is not fatal, as we'll fall back
* to software cursor. */
output->cursor_plane =
drm_output_find_special_plane(device, output,
WDRM_PLANE_TYPE_CURSOR);
if (output->cursor_plane)
weston_compositor_stack_plane(b->compositor,
&output->cursor_plane->base,
NULL);
else
device->cursors_are_broken = true;
return 0;
}
/** The opposite of drm_output_init_planes(). First of all it removes the planes
* from the plane stacking list. After all it sets the planes of the output as NULL.
*/
static void
drm_output_deinit_planes(struct drm_output *output)
{
struct drm_backend *b = output->backend;
struct drm_device *device = output->device;
/* If the compositor is already shutting down, the planes have already
* been destroyed. */
if (!b->compositor->shutting_down) {
wl_list_remove(&output->scanout_plane->base.link);
wl_list_init(&output->scanout_plane->base.link);
if (output->cursor_plane) {
wl_list_remove(&output->cursor_plane->base.link);
wl_list_init(&output->cursor_plane->base.link);
/* Turn off hardware cursor */
drmModeSetCursor(device->drm.fd, output->crtc->crtc_id, 0, 0, 0);
}
/* With universal planes, the planes are allocated at startup,
* freed at shutdown, and live on the plane list in between.
* We want the planes to continue to exist and be freed up
* for other outputs.
*/
if (output->cursor_plane)
drm_plane_reset_state(output->cursor_plane);
if (output->scanout_plane)
drm_plane_reset_state(output->scanout_plane);
}
output->cursor_plane = NULL;
output->scanout_plane = NULL;
}
backend-drm: add KMS plane's formats to per-surface dma-buf feedback In commit "libweston: add initial dma-buf feedback implementation" we've added initial support to dma-buf feedback, but it was not using the feedback from DRM-backend to add useful per-surface feedback. In this patch we add this. The scanout tranche of the per-surface feedback is based on the union of formats/modifiers of the primary and overlay planes available. These are intersected with the formats/modifiers supported by the renderer device. Also, it's important to mention that the scene can change a lot and we can't predict much. So this patch also adds hysteresis to the dma-buf feedback. We wait a few seconds to be sure that we reached stability before adding or removing the scanout tranche from dma-buf feedback and resending them. This help us to avoid spamming clients and leading to unnecessary buffer reallocations on their end. Here's an example of what we want to avoid: 1. We detect that a view was not placed in a plane only because its format is not supported by the plane, so we add the scanout tranche to the feedback and send the events. 2. A few milliseconds after, the view gets occluded. So now the view can't be placed in a plane anymore. We need to remove the scanout tranche and resend the feedback with formats/modifiers optimal for the renderer device. The client will then reallocate its buffers. 3. A few milliseconds after, the view that was causing the occlusion gets minimized. So we got back to the first situation, in which the format of the view is not compatible with the plane. Then we need to add a scanout tranche and resend the feedback... This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2021-10-12 17:48:36 +00:00
static struct weston_drm_format_array *
get_scanout_formats(struct drm_device *device)
backend-drm: add KMS plane's formats to per-surface dma-buf feedback In commit "libweston: add initial dma-buf feedback implementation" we've added initial support to dma-buf feedback, but it was not using the feedback from DRM-backend to add useful per-surface feedback. In this patch we add this. The scanout tranche of the per-surface feedback is based on the union of formats/modifiers of the primary and overlay planes available. These are intersected with the formats/modifiers supported by the renderer device. Also, it's important to mention that the scene can change a lot and we can't predict much. So this patch also adds hysteresis to the dma-buf feedback. We wait a few seconds to be sure that we reached stability before adding or removing the scanout tranche from dma-buf feedback and resending them. This help us to avoid spamming clients and leading to unnecessary buffer reallocations on their end. Here's an example of what we want to avoid: 1. We detect that a view was not placed in a plane only because its format is not supported by the plane, so we add the scanout tranche to the feedback and send the events. 2. A few milliseconds after, the view gets occluded. So now the view can't be placed in a plane anymore. We need to remove the scanout tranche and resend the feedback with formats/modifiers optimal for the renderer device. The client will then reallocate its buffers. 3. A few milliseconds after, the view that was causing the occlusion gets minimized. So we got back to the first situation, in which the format of the view is not compatible with the plane. Then we need to add a scanout tranche and resend the feedback... This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2021-10-12 17:48:36 +00:00
{
struct weston_compositor *ec = device->backend->compositor;
backend-drm: add KMS plane's formats to per-surface dma-buf feedback In commit "libweston: add initial dma-buf feedback implementation" we've added initial support to dma-buf feedback, but it was not using the feedback from DRM-backend to add useful per-surface feedback. In this patch we add this. The scanout tranche of the per-surface feedback is based on the union of formats/modifiers of the primary and overlay planes available. These are intersected with the formats/modifiers supported by the renderer device. Also, it's important to mention that the scene can change a lot and we can't predict much. So this patch also adds hysteresis to the dma-buf feedback. We wait a few seconds to be sure that we reached stability before adding or removing the scanout tranche from dma-buf feedback and resending them. This help us to avoid spamming clients and leading to unnecessary buffer reallocations on their end. Here's an example of what we want to avoid: 1. We detect that a view was not placed in a plane only because its format is not supported by the plane, so we add the scanout tranche to the feedback and send the events. 2. A few milliseconds after, the view gets occluded. So now the view can't be placed in a plane anymore. We need to remove the scanout tranche and resend the feedback with formats/modifiers optimal for the renderer device. The client will then reallocate its buffers. 3. A few milliseconds after, the view that was causing the occlusion gets minimized. So we got back to the first situation, in which the format of the view is not compatible with the plane. Then we need to add a scanout tranche and resend the feedback... This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2021-10-12 17:48:36 +00:00
const struct weston_drm_format_array *renderer_formats;
struct weston_drm_format_array *scanout_formats, union_planes_formats;
struct drm_plane *plane;
int ret;
/* If we got here it means that dma-buf feedback is supported and that
* the renderer has formats/modifiers to expose. */
assert(ec->renderer->get_supported_formats != NULL);
renderer_formats = ec->renderer->get_supported_formats(ec);
scanout_formats = zalloc(sizeof(*scanout_formats));
if (!scanout_formats) {
weston_log("%s: out of memory\n", __func__);
return NULL;
}
weston_drm_format_array_init(&union_planes_formats);
weston_drm_format_array_init(scanout_formats);
/* Compute the union of the format/modifiers of the KMS planes */
wl_list_for_each(plane, &device->plane_list, link) {
backend-drm: add KMS plane's formats to per-surface dma-buf feedback In commit "libweston: add initial dma-buf feedback implementation" we've added initial support to dma-buf feedback, but it was not using the feedback from DRM-backend to add useful per-surface feedback. In this patch we add this. The scanout tranche of the per-surface feedback is based on the union of formats/modifiers of the primary and overlay planes available. These are intersected with the formats/modifiers supported by the renderer device. Also, it's important to mention that the scene can change a lot and we can't predict much. So this patch also adds hysteresis to the dma-buf feedback. We wait a few seconds to be sure that we reached stability before adding or removing the scanout tranche from dma-buf feedback and resending them. This help us to avoid spamming clients and leading to unnecessary buffer reallocations on their end. Here's an example of what we want to avoid: 1. We detect that a view was not placed in a plane only because its format is not supported by the plane, so we add the scanout tranche to the feedback and send the events. 2. A few milliseconds after, the view gets occluded. So now the view can't be placed in a plane anymore. We need to remove the scanout tranche and resend the feedback with formats/modifiers optimal for the renderer device. The client will then reallocate its buffers. 3. A few milliseconds after, the view that was causing the occlusion gets minimized. So we got back to the first situation, in which the format of the view is not compatible with the plane. Then we need to add a scanout tranche and resend the feedback... This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2021-10-12 17:48:36 +00:00
/* The scanout formats are used by the dma-buf feedback. But for
* now cursor planes do not support dma-buf buffers, only wl_shm
* buffers. So we skip cursor planes here. */
if (plane->type == WDRM_PLANE_TYPE_CURSOR)
continue;
ret = weston_drm_format_array_join(&union_planes_formats,
&plane->formats);
if (ret < 0)
goto err;
}
/* Compute the intersection between the union of format/modifiers of KMS
* planes and the formats supported by the renderer */
ret = weston_drm_format_array_replace(scanout_formats,
renderer_formats);
if (ret < 0)
goto err;
ret = weston_drm_format_array_intersect(scanout_formats,
&union_planes_formats);
if (ret < 0)
goto err;
weston_drm_format_array_fini(&union_planes_formats);
return scanout_formats;
err:
weston_drm_format_array_fini(&union_planes_formats);
weston_drm_format_array_fini(scanout_formats);
free(scanout_formats);
backend-drm: add KMS plane's formats to per-surface dma-buf feedback In commit "libweston: add initial dma-buf feedback implementation" we've added initial support to dma-buf feedback, but it was not using the feedback from DRM-backend to add useful per-surface feedback. In this patch we add this. The scanout tranche of the per-surface feedback is based on the union of formats/modifiers of the primary and overlay planes available. These are intersected with the formats/modifiers supported by the renderer device. Also, it's important to mention that the scene can change a lot and we can't predict much. So this patch also adds hysteresis to the dma-buf feedback. We wait a few seconds to be sure that we reached stability before adding or removing the scanout tranche from dma-buf feedback and resending them. This help us to avoid spamming clients and leading to unnecessary buffer reallocations on their end. Here's an example of what we want to avoid: 1. We detect that a view was not placed in a plane only because its format is not supported by the plane, so we add the scanout tranche to the feedback and send the events. 2. A few milliseconds after, the view gets occluded. So now the view can't be placed in a plane anymore. We need to remove the scanout tranche and resend the feedback with formats/modifiers optimal for the renderer device. The client will then reallocate its buffers. 3. A few milliseconds after, the view that was causing the occlusion gets minimized. So we got back to the first situation, in which the format of the view is not compatible with the plane. Then we need to add a scanout tranche and resend the feedback... This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2021-10-12 17:48:36 +00:00
return NULL;
}
/** Pick a CRTC and reserve it for the output.
*
* On failure, the output remains without a CRTC.
*
* @param output The output with no CRTC associated.
* @return 0 on success, -1 on failure.
*/
static int
drm_output_attach_crtc(struct drm_output *output)
{
output->crtc = drm_output_pick_crtc(output);
if (!output->crtc) {
weston_log("Output '%s': No available CRTCs.\n",
output->base.name);
return -1;
}
/* Reserve the CRTC for the output */
output->crtc->output = output;
return 0;
}
/** Release reservation of the CRTC.
*
* Make the CRTC free to be reserved and used by another output.
*
* @param output The output that will release its CRTC.
*/
static void
drm_output_detach_crtc(struct drm_output *output)
{
struct drm_crtc *crtc = output->crtc;
crtc->output = NULL;
output->crtc = NULL;
}
static bool
should_wait_drm_events(struct drm_device *device)
{
struct weston_output *base;
struct drm_output *output;
wl_list_for_each(base, &device->backend->compositor->output_list, link) {
/* We only care about outputs related to the DRM backend. */
output = to_drm_output(base);
if (!output)
continue;
/* We only care about the outputs on our device. */
if (output->device != device)
continue;
if (output->destroy_pending || output->disable_pending)
return true;
}
return false;
}
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
static int
drm_output_enable(struct weston_output *base)
{
struct drm_output *output = to_drm_output(base);
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
int ret;
assert(output);
assert(!output->virtual);
/* TODO: drop this hack when we rework the output configuration API. For
* now we need this because the frontend may call
* weston_output_destroy() or weston_output_disable() but it may have a
* pending page flip. In such case the destruction is delayed, but the
* frontend can't tell that. Until the flip completes, the DRM objects
* of the card (CRTC, planes, etc) won't be available, as they will
* still be attached to the output marked to be destroyed/disabled. So
* if the frontend calls weston_output_enable() for an output right
* after weston_output_destroy() or weston_output_disable(), it might
* not find DRM objects available and fail. So we spin here until the
* flip completes and the output gets destroyed/disabled and release the
* DRM objects. */
while (should_wait_drm_events(device))
on_drm_input(device->drm.fd, 0 /* unused mask */, device);
if (!output->format) {
if (output->base.eotf_mode != WESTON_EOTF_MODE_SDR)
output->format =
pixel_format_get_info(DRM_FORMAT_XRGB2101010);
else
output->format = b->format;
}
ret = drm_output_attach_crtc(output);
if (ret < 0)
return -1;
ret = drm_output_init_planes(output);
if (ret < 0)
goto err_crtc;
if (drm_output_init_gamma_size(output) < 0)
goto err_planes;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
compositor-drm: pageflip timeout implementation Weston will not repaint until previous update has been acked by a pageflip event coming from the drm driver. However, some buggy drivers won’t return those events or will stop sending them at some point and Weston output repaints will completely freeze. To ease developers’ task in testing their drivers, this patch makes compositor-drm use a timer to detect cases where those pageflip events stop coming. This timeout implementation is software only and includes basic features usually found in a watchdog. We simply exit Weston gracefully with a log message and an exit code when the timout is reached. The timeout value can be set via weston.ini by adding a pageflip-timeout=<MILLISECONDS> entry under [core] section. Setting it to 0 disables the timeout feature. v2: - Made sure we would get both the pageflip and the vblank events before stopping the timer. - Reordered the error and success cases in drm_output_pageflip_timer_create() to be more in line with the rest of the code. v3: - Reordered (de)arming of the timer with the code around it to avoid it being rearmed before the current dearming. - Return the proper value for the dispatcher in the pageflip_timeout callback. - Also display the output name in case the timer fires. v4: - Reordered a forgotten timer rearming after its drmModePageFlip(). Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=83884 Signed-off-by: Frederic Plourde <frederic.plourde at collabora.co.uk> Signed-off-by: Emmanuel Gil Peyrot <emmanuel.peyrot@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2017-03-07 13:27:54 +00:00
if (b->pageflip_timeout)
drm_output_pageflip_timer_create(output);
if (b->compositor->renderer->type == WESTON_RENDERER_PIXMAN) {
if (drm_output_init_pixman(output, b) < 0) {
weston_log("Failed to init output pixman state\n");
goto err_planes;
}
} else if (drm_output_init_egl(output, b) < 0) {
weston_log("Failed to init output gl state\n");
goto err_planes;
}
2012-05-03 15:39:35 +00:00
drm_output_init_backlight(output);
output->base.start_repaint_loop = drm_output_start_repaint_loop;
output->base.repaint = drm_output_repaint;
output->base.assign_planes = drm_assign_planes;
output->base.set_dpms = drm_set_dpms;
output->base.switch_mode = drm_output_switch_mode;
2013-05-01 20:52:12 +00:00
output->base.set_gamma = drm_output_set_gamma;
if (device->atomic_modeset)
weston_output_update_capture_info(base, WESTON_OUTPUT_CAPTURE_SOURCE_WRITEBACK,
base->current_mode->width,
base->current_mode->height,
pixel_format_get_info(output->format->format));
weston_log("Output %s (crtc %d) video modes:\n",
output->base.name, output->crtc->crtc_id);
drm_output_print_modes(output);
return 0;
err_planes:
drm_output_deinit_planes(output);
err_crtc:
drm_output_detach_crtc(output);
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
return -1;
}
static void
drm_output_deinit(struct weston_output *base)
{
struct drm_output *output = to_drm_output(base);
struct drm_backend *b = output->backend;
struct drm_device *device = output->device;
struct drm_pending_state *pending;
if (!b->compositor->shutting_down) {
pending = drm_pending_state_alloc(device);
drm_output_get_disable_state(pending, output);
drm_pending_state_apply_sync(pending);
}
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
if (b->compositor->renderer->type == WESTON_RENDERER_PIXMAN)
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
drm_output_fini_pixman(output);
else
drm_output_fini_egl(output);
drm_output_deinit_planes(output);
drm_output_detach_crtc(output);
if (output->hdr_output_metadata_blob_id) {
drmModeDestroyPropertyBlob(device->drm.fd,
output->hdr_output_metadata_blob_id);
output->hdr_output_metadata_blob_id = 0;
}
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
}
void
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
drm_output_destroy(struct weston_output *base)
{
struct drm_output *output = to_drm_output(base);
struct drm_device *device = output->device;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
assert(output);
assert(!output->virtual);
if (output->page_flip_pending || output->atomic_complete_pending) {
if (!base->compositor->shutting_down) {
/* We are not shutting down, so we can wait for flip
* completion. */
output->destroy_pending = true;
weston_log("delaying output destruction because of a " \
"pending flip, wait until it completes\n");
return;
} else {
weston_log("destroying output %s (id %u) with a pending " \
"flip, but as we are shutting down we can't " \
"wait to destroy it when the flip completes... " \
"destroying it now\n", base->name, base->id);
}
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
}
drm_output_set_cursor_view(output, NULL);
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
if (output->base.enabled)
drm_output_deinit(&output->base);
drm_mode_list_destroy(device, &output->base.mode_list);
compositor-drm: pageflip timeout implementation Weston will not repaint until previous update has been acked by a pageflip event coming from the drm driver. However, some buggy drivers won’t return those events or will stop sending them at some point and Weston output repaints will completely freeze. To ease developers’ task in testing their drivers, this patch makes compositor-drm use a timer to detect cases where those pageflip events stop coming. This timeout implementation is software only and includes basic features usually found in a watchdog. We simply exit Weston gracefully with a log message and an exit code when the timout is reached. The timeout value can be set via weston.ini by adding a pageflip-timeout=<MILLISECONDS> entry under [core] section. Setting it to 0 disables the timeout feature. v2: - Made sure we would get both the pageflip and the vblank events before stopping the timer. - Reordered the error and success cases in drm_output_pageflip_timer_create() to be more in line with the rest of the code. v3: - Reordered (de)arming of the timer with the code around it to avoid it being rearmed before the current dearming. - Return the proper value for the dispatcher in the pageflip_timeout callback. - Also display the output name in case the timer fires. v4: - Reordered a forgotten timer rearming after its drmModePageFlip(). Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=83884 Signed-off-by: Frederic Plourde <frederic.plourde at collabora.co.uk> Signed-off-by: Emmanuel Gil Peyrot <emmanuel.peyrot@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2017-03-07 13:27:54 +00:00
if (output->pageflip_timer)
wl_event_source_remove(output->pageflip_timer);
weston_output_release(&output->base);
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
assert(!output->state_last);
drm_output_state_free(output->state_cur);
assert(output->hdr_output_metadata_blob_id == 0);
free(output);
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
}
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
static int
drm_output_disable(struct weston_output *base)
{
struct drm_output *output = to_drm_output(base);
assert(output);
assert(!output->virtual);
if (output->page_flip_pending || output->atomic_complete_pending) {
output->disable_pending = true;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
return -1;
}
weston_log("Disabling output %s\n", output->base.name);
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
if (output->base.enabled)
drm_output_deinit(&output->base);
output->disable_pending = false;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
return 0;
}
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
/*
* This function converts the protection status from drm values to
* weston_hdcp_protection status. The drm values as read from the connector
* properties "Content Protection" and "HDCP Content Type" need to be converted
* to appropriate weston values, that can be sent to a client application.
*/
static int
get_weston_protection_from_drm(enum wdrm_content_protection_state protection,
enum wdrm_hdcp_content_type type,
enum weston_hdcp_protection *weston_protection)
{
if (protection >= WDRM_CONTENT_PROTECTION__COUNT)
return -1;
if (protection == WDRM_CONTENT_PROTECTION_DESIRED ||
protection == WDRM_CONTENT_PROTECTION_UNDESIRED) {
*weston_protection = WESTON_HDCP_DISABLE;
return 0;
}
if (type >= WDRM_HDCP_CONTENT_TYPE__COUNT)
return -1;
if (type == WDRM_HDCP_CONTENT_TYPE0) {
*weston_protection = WESTON_HDCP_ENABLE_TYPE_0;
return 0;
}
if (type == WDRM_HDCP_CONTENT_TYPE1) {
*weston_protection = WESTON_HDCP_ENABLE_TYPE_1;
return 0;
}
return -1;
}
/**
* Get current content-protection status for a given head.
*
* @param head drm_head, whose protection is to be retrieved
* @return protection status in case of success, -1 otherwise
*/
static enum weston_hdcp_protection
drm_head_get_current_protection(struct drm_head *head)
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
{
drmModeObjectProperties *props = head->connector.props_drm;
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
struct drm_property_info *info;
enum wdrm_content_protection_state protection;
enum wdrm_hdcp_content_type type;
enum weston_hdcp_protection weston_hdcp = WESTON_HDCP_DISABLE;
info = &head->connector.props[WDRM_CONNECTOR_CONTENT_PROTECTION];
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
protection = drm_property_get_value(info, props,
WDRM_CONTENT_PROTECTION__COUNT);
if (protection == WDRM_CONTENT_PROTECTION__COUNT)
return WESTON_HDCP_DISABLE;
info = &head->connector.props[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
type = drm_property_get_value(info, props,
WDRM_HDCP_CONTENT_TYPE__COUNT);
/*
* In case of platforms supporting HDCP1.4, only property
* 'Content Protection' is exposed and not the 'HDCP Content Type'
* for such cases HDCP Type 0 should be considered as the content-type.
*/
if (type == WDRM_HDCP_CONTENT_TYPE__COUNT)
type = WDRM_HDCP_CONTENT_TYPE0;
if (get_weston_protection_from_drm(protection, type,
&weston_hdcp) == -1) {
weston_log("Invalid drm protection:%d type:%d, for head:%s connector-id:%d\n",
protection, type, head->base.name,
head->connector.connector_id);
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
return WESTON_HDCP_DISABLE;
}
return weston_hdcp;
}
static int
drm_connector_update_properties(struct drm_connector *connector)
{
struct drm_device *device = connector->device;
drmModeObjectProperties *props;
props = drmModeObjectGetProperties(device->drm.fd,
connector->connector_id,
DRM_MODE_OBJECT_CONNECTOR);
if (!props) {
weston_log("Error: failed to get connector properties\n");
return -1;
}
if (connector->props_drm)
drmModeFreeObjectProperties(connector->props_drm);
connector->props_drm = props;
return 0;
}
/** Replace connector data and monitor information
*
* @param connector The drm_connector object to be updated.
* @param conn The connector data to be owned by the drm_connector, must match
* the current drm_connector ID.
* @return 0 on success, -1 on failure.
*
* Takes ownership of @c connector on success, not on failure.
*/
static int
drm_connector_assign_connector_info(struct drm_connector *connector,
drmModeConnector *conn)
{
struct drm_device *device = connector->device;
assert(connector->conn != conn);
assert(connector->connector_id == conn->connector_id);
if (drm_connector_update_properties(connector) < 0)
return -1;
if (connector->conn)
drmModeFreeConnector(connector->conn);
connector->conn = conn;
drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
drm_property_info_populate(device, connector_props, connector->props,
WDRM_CONNECTOR__COUNT, connector->props_drm);
return 0;
}
static void
drm_connector_init(struct drm_device *device, struct drm_connector *connector,
uint32_t connector_id)
{
connector->device = device;
connector->connector_id = connector_id;
connector->conn = NULL;
connector->props_drm = NULL;
}
static void
drm_connector_fini(struct drm_connector *connector)
{
drmModeFreeConnector(connector->conn);
drmModeFreeObjectProperties(connector->props_drm);
drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
}
static void
drm_head_log_info(struct drm_head *head, const char *msg)
{
char *str;
if (head->base.connected) {
weston_log("DRM: head '%s' %s, connector %d is connected, "
"EDID make '%s', model '%s', serial '%s'\n",
head->base.name, msg, head->connector.connector_id,
head->base.make, head->base.model,
head->base.serial_number ?: "");
str = weston_eotf_mask_to_str(head->base.supported_eotf_mask);
if (str) {
weston_log_continue(STAMP_SPACE
"Supported EOTF modes: %s\n",
str);
}
free(str);
} else {
weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
head->base.name, msg, head->connector.connector_id);
}
}
/** Update connector and monitor information
*
* @param head The head to update.
* @param conn The DRM connector object.
* @returns 0 on success, -1 on failure.
*
* Updates monitor information and connection status. This may schedule a
* heads changed call to the user.
*
* Takes ownership of @c connector on success, not on failure.
*/
static int
drm_head_update_info(struct drm_head *head, drmModeConnector *conn)
{
int ret;
ret = drm_connector_assign_connector_info(&head->connector, conn);
update_head_from_connector(head);
weston_head_set_content_protection_status(&head->base,
drm_head_get_current_protection(head));
return ret;
}
/** Update writeback connector
*
* @param writeback The writeback to update.
* @param conn DRM connector object.
* @returns 0 on success, -1 on failure.
*
* Takes ownership of @c connector on success, not on failure.
*/
static int
drm_writeback_update_info(struct drm_writeback *writeback, drmModeConnector *conn)
{
int ret;
ret = drm_connector_assign_connector_info(&writeback->connector, conn);
return ret;
}
/**
* Create a Weston head for a connector
*
* Given a DRM connector, create a matching drm_head structure and add it
* to Weston's head list.
*
* @param device DRM device structure
* @param conn DRM connector object
* @param drm_device udev device pointer
* @returns 0 on success, -1 on failure
*
* Takes ownership of @c connector on success, not on failure.
*/
static int
drm_head_create(struct drm_device *device, drmModeConnector *conn,
struct udev_device *drm_device)
{
struct drm_backend *backend = device->backend;
struct drm_head *head;
char *name;
int ret;
head = zalloc(sizeof *head);
if (!head)
return -1;
drm_connector_init(device, &head->connector, conn->connector_id);
name = make_connector_name(conn);
if (!name)
goto err;
weston_head_init(&head->base, name);
free(name);
head->base.backend = &backend->base;
wl_list_init(&head->disable_head_link);
ret = drm_head_update_info(head, conn);
if (ret < 0)
goto err_update;
head->backlight = backlight_init(drm_device, conn->connector_type);
if (conn->connector_type == DRM_MODE_CONNECTOR_LVDS ||
conn->connector_type == DRM_MODE_CONNECTOR_eDP)
weston_head_set_internal(&head->base);
if (drm_head_read_current_setup(head, device) < 0) {
weston_log("Failed to retrieve current mode from connector %d.\n",
head->connector.connector_id);
/* Not fatal. */
}
weston_compositor_add_head(backend->compositor, &head->base);
drm_head_log_info(head, "found");
return 0;
err_update:
weston_head_release(&head->base);
err:
drm_connector_fini(&head->connector);
free(head);
return -1;
}
static void
drm_head_destroy(struct weston_head *base)
{
struct drm_head *head = to_drm_head(base);
assert(head);
weston_head_release(&head->base);
drm_connector_fini(&head->connector);
if (head->backlight)
backlight_destroy(head->backlight);
free(head->display_data);
free(head);
}
static struct drm_device *
drm_device_find_by_output(struct weston_compositor *compositor, const char *name)
{
struct drm_device *device = NULL;
struct weston_head *base = NULL;
struct drm_head *head;
const char *tmp;
while ((base = weston_compositor_iterate_heads(compositor, base))) {
tmp = weston_head_get_name(base);
if (strcmp(name, tmp) != 0)
continue;
head = to_drm_head(base);
device = head->connector.device;
break;
}
return device;
}
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
/**
* Create a Weston output structure
*
* Create an "empty" drm_output. This is the implementation of
* weston_backend::create_output.
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
*
* Creating an output is usually followed by drm_output_attach_head()
* and drm_output_enable() to make use of it.
*
* @param backend The backend instance.
* @param name Name for the new output.
* @returns The output, or NULL on failure.
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
*/
static struct weston_output *
drm_output_create(struct weston_backend *backend, const char *name)
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
{
struct drm_backend *b = container_of(backend, struct drm_backend, base);
struct drm_device *device;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
struct drm_output *output;
device = drm_device_find_by_output(b->compositor, name);
if (!device)
return NULL;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
output = zalloc(sizeof *output);
if (output == NULL)
return NULL;
output->device = device;
output->crtc = NULL;
wl_list_init(&output->disable_head);
output->max_bpc = 16;
#ifdef BUILD_DRM_GBM
output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
#endif
weston_output_init(&output->base, b->compositor, name);
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
output->base.enable = drm_output_enable;
output->base.destroy = drm_output_destroy;
output->base.disable = drm_output_disable;
output->base.attach_head = drm_output_attach_head;
output->base.detach_head = drm_output_detach_head;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
output->backend = b;
output->destroy_pending = false;
output->disable_pending = false;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
output->state_cur = drm_output_state_alloc(output, NULL);
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
weston_compositor_add_pending_output(&output->base, b->compositor);
return &output->base;
}
static void
pixman_copy_screenshot(uint32_t *dst, uint32_t *src, int dst_stride,
int src_stride, int pixman_format, int width, int height)
{
pixman_image_t *pixman_dst;
pixman_image_t *pixman_src;
pixman_src = pixman_image_create_bits(pixman_format,
width, height,
src, src_stride);
pixman_dst = pixman_image_create_bits(pixman_format,
width, height,
dst, dst_stride);
assert(pixman_src);
assert(pixman_dst);
pixman_image_composite32(PIXMAN_OP_SRC,
pixman_src, /* src */
NULL, /* mask */
pixman_dst, /* dst */
0, 0, /* src_x, src_y */
0, 0, /* mask_x, mask_y */
0, 0, /* dst_x, dst_y */
width, height); /* width, height */
pixman_image_unref(pixman_src);
pixman_image_unref(pixman_dst);
}
static void
drm_writeback_success_screenshot(struct drm_writeback_state *state)
{
struct drm_output *output = state->output;
struct weston_buffer *buffer =
weston_capture_task_get_buffer(state->ct);
int width, height;
int dst_stride, src_stride;
uint32_t *src, *dst;
src = state->fb->map;
src_stride = state->fb->strides[0];
dst = wl_shm_buffer_get_data(buffer->shm_buffer);
dst_stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
width = state->fb->width;
height = state->fb->height;
wl_shm_buffer_begin_access(buffer->shm_buffer);
pixman_copy_screenshot(dst, src, dst_stride, src_stride,
buffer->pixel_format->pixman_format,
width, height);
wl_shm_buffer_end_access(buffer->shm_buffer);
weston_capture_task_retire_complete(state->ct);
drm_writeback_state_free(state);
output->wb_state = NULL;
}
void
drm_writeback_fail_screenshot(struct drm_writeback_state *state,
const char *err_msg)
{
struct drm_output *output = state->output;
weston_capture_task_retire_failed(state->ct, err_msg);
drm_writeback_state_free(state);
output->wb_state = NULL;
}
static int
drm_writeback_save_callback(int fd, uint32_t mask, void *data)
{
struct drm_writeback_state *state = data;
wl_event_source_remove(state->wb_source);
close(fd);
drm_writeback_success_screenshot(state);
return 0;
}
static bool
drm_writeback_has_finished(struct drm_writeback_state *state)
{
struct pollfd pollfd;
int ret;
pollfd.fd = state->out_fence_fd;
pollfd.events = POLLIN;
while ((ret = poll(&pollfd, 1, 0)) == -1 && errno == EINTR)
continue;
if (ret < 0) {
drm_writeback_fail_screenshot(state, "drm: polling wb fence failed");
return true;
} else if (ret > 0) {
/* fence already signaled, simply save the screenshot */
drm_writeback_success_screenshot(state);
return true;
}
/* poll() returned 0, what means that out fence was not signalled yet */
return false;
}
bool
drm_writeback_should_wait_completion(struct drm_writeback_state *state)
{
struct weston_compositor *ec = state->output->base.compositor;
struct wl_event_loop *event_loop;
if (state->state == DRM_OUTPUT_WB_SCREENSHOT_WAITING_SIGNAL)
return true;
if (state->state == DRM_OUTPUT_WB_SCREENSHOT_CHECK_FENCE) {
if (drm_writeback_has_finished(state))
return false;
/* The writeback has not finished yet. So add callback that gets
* called when the sync fd of the writeback job gets signalled.
* We need to wait for that to resume the repaint loop. */
event_loop = wl_display_get_event_loop(ec->wl_display);
state->wb_source =
wl_event_loop_add_fd(event_loop, state->out_fence_fd,
WL_EVENT_READABLE,
drm_writeback_save_callback, state);
if (!state->wb_source) {
drm_writeback_fail_screenshot(state, "drm: out of memory");
return false;
}
state->state = DRM_OUTPUT_WB_SCREENSHOT_WAITING_SIGNAL;
return true;
}
return false;
}
void
drm_writeback_reference_planes(struct drm_writeback_state *state,
struct wl_list *plane_state_list)
{
struct drm_plane_state *plane_state;
struct drm_fb **fb;
wl_list_for_each(plane_state, plane_state_list, link) {
if (!plane_state->fb)
continue;
fb = wl_array_add(&state->referenced_fbs, sizeof(*fb));
*fb = drm_fb_ref(plane_state->fb);
}
}
static int
drm_writeback_populate_formats(struct drm_writeback *wb)
{
struct drm_property_info *info = wb->connector.props;
drmModeObjectProperties *props = wb->connector.props_drm;
uint64_t blob_id;
drmModePropertyBlobPtr blob;
uint32_t *blob_formats;
unsigned int i;
int ret = 0;
blob_id = drm_property_get_value(&info[WDRM_CONNECTOR_WRITEBACK_PIXEL_FORMATS],
props, 0);
if (blob_id == 0)
return -1;
blob = drmModeGetPropertyBlob(wb->device->drm.fd, blob_id);
if (!blob)
return -1;
blob_formats = blob->data;
for (i = 0; i < blob->length / sizeof(uint32_t); i++) {
if (!weston_drm_format_array_add_format(&wb->formats,
blob_formats[i])) {
ret = -1;
break;
}
}
drmModeFreePropertyBlob(blob);
return ret;
}
/**
* Create a Weston writeback for a writeback connector
*
* Given a DRM connector of type writeback, create a matching drm_writeback
* structure and add it to Weston's writeback list.
*
* @param device DRM device structure
* @param conn DRM connector object of type writeback
* @returns 0 on success, -1 on failure
*
* Takes ownership of @c connector on success, not on failure.
*/
static int
drm_writeback_create(struct drm_device *device, drmModeConnector *conn)
{
struct drm_writeback *writeback;
int ret;
writeback = zalloc(sizeof *writeback);
assert(writeback);
writeback->device = device;
drm_connector_init(device, &writeback->connector, conn->connector_id);
ret = drm_writeback_update_info(writeback, conn);
if (ret < 0)
goto err;
weston_drm_format_array_init(&writeback->formats);
ret = drm_writeback_populate_formats(writeback);
if (ret < 0)
goto err_formats;
wl_list_insert(&device->writeback_connector_list, &writeback->link);
return 0;
err_formats:
weston_drm_format_array_fini(&writeback->formats);
err:
drm_connector_fini(&writeback->connector);
free(writeback);
return -1;
}
static void
drm_writeback_destroy(struct drm_writeback *writeback)
{
drm_connector_fini(&writeback->connector);
weston_drm_format_array_fini(&writeback->formats);
wl_list_remove(&writeback->link);
free(writeback);
}
/** Given the DRM connector object of a connector, create drm_head or
* drm_writeback object (depending on the type of connector) for it.
*
* The object is then added to the DRM-backend list of heads or writebacks.
*
* @param device The DRM device structure
* @param conn The DRM connector object
* @param drm_device udev device pointer
* @return 0 on success, -1 on failure
*/
static int
drm_backend_add_connector(struct drm_device *device, drmModeConnector *conn,
struct udev_device *drm_device)
{
int ret;
if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) {
ret = drm_writeback_create(device, conn);
if (ret < 0)
weston_log("DRM: failed to create writeback for connector %d.\n",
conn->connector_id);
} else {
ret = drm_head_create(device, conn, drm_device);
if (ret < 0)
weston_log("DRM: failed to create head for connector %d.\n",
conn->connector_id);
}
return ret;
}
/** Find all connectors of the fd and create drm_head or drm_writeback objects
* (depending on the type of connector they are) for each of them
*
* These objects are added to the DRM-backend lists of heads and writebacks.
*
* @param device The DRM device structure
* @param drm_device udev device pointer
* @param resources The DRM resources, it is taken with drmModeGetResources
* @return 0 on success, -1 on failure
*/
static int
drm_backend_discover_connectors(struct drm_device *device,
struct udev_device *drm_device,
drmModeRes *resources)
{
drmModeConnector *conn;
int i, ret;
device->min_width = resources->min_width;
device->max_width = resources->max_width;
device->min_height = resources->min_height;
device->max_height = resources->max_height;
for (i = 0; i < resources->count_connectors; i++) {
uint32_t connector_id = resources->connectors[i];
conn = drmModeGetConnector(device->drm.fd, connector_id);
if (!conn)
continue;
ret = drm_backend_add_connector(device, conn, drm_device);
if (ret < 0)
drmModeFreeConnector(conn);
}
return 0;
}
static bool
resources_has_connector(drmModeRes *resources, uint32_t connector_id)
{
for (int i = 0; i < resources->count_connectors; i++) {
if (resources->connectors[i] == connector_id)
return true;
}
return false;
}
static void
drm_backend_update_connectors(struct drm_device *device,
struct udev_device *drm_device)
{
struct drm_backend *b = device->backend;
drmModeRes *resources;
drmModeConnector *conn;
struct weston_head *base, *base_next;
struct drm_head *head;
struct drm_writeback *writeback, *writeback_next;
uint32_t connector_id;
int i, ret;
resources = drmModeGetResources(device->drm.fd);
if (!resources) {
2012-06-07 16:01:59 +00:00
weston_log("drmModeGetResources failed\n");
return;
}
/* collect new connectors that have appeared, e.g. MST */
for (i = 0; i < resources->count_connectors; i++) {
connector_id = resources->connectors[i];
conn = drmModeGetConnector(device->drm.fd, connector_id);
if (!conn)
continue;
head = drm_head_find_by_connector(b, device, connector_id);
writeback = drm_writeback_find_by_connector(device, connector_id);
/* Connector can't be owned by both a head and a writeback, so
* one of the searches must fail. */
assert(head == NULL || writeback == NULL);
if (head) {
ret = drm_head_update_info(head, conn);
if (head->base.device_changed)
drm_head_log_info(head, "updated");
} else if (writeback) {
ret = drm_writeback_update_info(writeback, conn);
} else {
ret = drm_backend_add_connector(device, conn, drm_device);
}
if (ret < 0)
drmModeFreeConnector(conn);
}
/* Destroy head objects of connectors (except writeback connectors) that
* have disappeared. */
wl_list_for_each_safe(base, base_next,
&b->compositor->head_list, compositor_link) {
head = to_drm_head(base);
if (!head)
continue;
connector_id = head->connector.connector_id;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
if (head->connector.device != device)
continue;
if (resources_has_connector(resources, connector_id))
continue;
weston_log("DRM: head '%s' (connector %d) disappeared.\n",
head->base.name, connector_id);
drm_head_destroy(base);
}
/* Destroy writeback objects of writeback connectors that have
* disappeared. */
wl_list_for_each_safe(writeback, writeback_next,
&b->drm->writeback_connector_list, link) {
connector_id = writeback->connector.connector_id;
if (resources_has_connector(resources, connector_id))
continue;
weston_log("DRM: writeback connector (connector %d) disappeared.\n",
connector_id);
drm_writeback_destroy(writeback);
}
drmModeFreeResources(resources);
}
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
static enum wdrm_connector_property
drm_connector_find_property_by_id(struct drm_connector *connector,
uint32_t property_id)
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
{
int i;
enum wdrm_connector_property prop = WDRM_CONNECTOR__COUNT;
if (!connector || !property_id)
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
return WDRM_CONNECTOR__COUNT;
for (i = 0; i < WDRM_CONNECTOR__COUNT; i++)
if (connector->props[i].prop_id == property_id) {
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
prop = (enum wdrm_connector_property) i;
break;
}
return prop;
}
static void
drm_backend_update_conn_props(struct drm_backend *b,
struct drm_device *device,
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
uint32_t connector_id,
uint32_t property_id)
{
struct drm_head *head;
enum wdrm_connector_property conn_prop;
head = drm_head_find_by_connector(b, device, connector_id);
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
if (!head) {
weston_log("DRM: failed to find head for connector id: %d.\n",
connector_id);
return;
}
conn_prop = drm_connector_find_property_by_id(&head->connector, property_id);
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
if (conn_prop >= WDRM_CONNECTOR__COUNT)
return;
if (drm_connector_update_properties(&head->connector) < 0)
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
return;
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
if (conn_prop == WDRM_CONNECTOR_CONTENT_PROTECTION) {
weston_head_set_content_protection_status(&head->base,
drm_head_get_current_protection(head));
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
}
}
static int
udev_event_is_hotplug(struct drm_device *device, struct udev_device *udev_device)
{
const char *sysnum;
const char *val;
sysnum = udev_device_get_sysnum(udev_device);
if (!sysnum || atoi(sysnum) != device->drm.id)
return 0;
val = udev_device_get_property_value(udev_device, "HOTPLUG");
if (!val)
return 0;
return strcmp(val, "1") == 0;
}
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
static int
udev_event_is_conn_prop_change(struct drm_backend *b,
struct udev_device *udev_device,
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
uint32_t *connector_id,
uint32_t *property_id)
{
const char *val;
int id;
val = udev_device_get_property_value(udev_device, "CONNECTOR");
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
if (!val || !safe_strtoint(val, &id))
return 0;
else
*connector_id = id;
val = udev_device_get_property_value(udev_device, "PROPERTY");
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
if (!val || !safe_strtoint(val, &id))
return 0;
else
*property_id = id;
return 1;
}
static int
udev_drm_event(int fd, uint32_t mask, void *data)
{
struct drm_backend *b = data;
struct udev_device *event;
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
uint32_t conn_id, prop_id;
struct drm_device *device;
event = udev_monitor_receive_device(b->udev_monitor);
if (udev_event_is_hotplug(b->drm, event)) {
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id))
drm_backend_update_conn_props(b, b->drm, conn_id, prop_id);
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
else
drm_backend_update_connectors(b->drm, event);
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
}
wl_list_for_each(device, &b->kms_list, link) {
if (udev_event_is_hotplug(device, event)) {
if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id))
drm_backend_update_conn_props(b, device, conn_id, prop_id);
else
drm_backend_update_connectors(device, event);
}
}
udev_device_unref(event);
return 1;
}
static void
drm_shutdown(struct weston_backend *backend)
{
struct drm_backend *b = container_of(backend, struct drm_backend, base);
struct weston_compositor *ec = b->compositor;
struct weston_output *output_base;
struct drm_output *output;
udev_input_destroy(&b->input);
wl_event_source_remove(b->udev_drm_source);
wl_event_source_remove(b->drm_source);
/* We are shutting down. This function destroy the planes with
* destroy_sprites() and then calls weston_compositor_shutdown(), which
* will lead to calls to drm_output_destroy(). We are destroying the
* plane and its state_cur in drm_plane_destroy(), and that removes
* state_cur from the output->state_cur list, but not from the
* state_last list.
*
* This was not an issue because we'd leak the drm_output (and so
* output->last_state) during shutdown with a pending page flip. And if
* we were no shutting down, we'd always wait until flip completion
* before destroying an output (meaning that
* drm_output_update_complete() would be called and output->state_last
* would be freed and set to NULL).
*
* But now we don't leak the drm_output during shutdown with a pending
* flip anymore. So we must destroy output->state_last for every output
* before destroying the planes with destroy_sprites(), otherwise we'd
* leave output->state_last referring to a freed plane, leading to
* issues when trying to free it at a later point.
*/
wl_list_for_each(output_base, &ec->output_list, link) {
output = to_drm_output(output_base);
if (output && (output->page_flip_pending || output->atomic_complete_pending)) {
drm_output_state_free(output->state_last);
output->state_last = NULL;
}
}
destroy_sprites(b->drm);
weston_log_scope_destroy(b->debug);
b->debug = NULL;
}
void
drm_destroy(struct weston_backend *backend)
{
struct drm_backend *b = container_of(backend, struct drm_backend, base);
struct weston_compositor *ec = b->compositor;
struct drm_device *device = b->drm;
struct weston_head *base, *next;
struct drm_crtc *crtc, *crtc_tmp;
struct drm_writeback *writeback, *writeback_tmp;
wl_list_remove(&b->base.link);
wl_list_for_each_safe(crtc, crtc_tmp, &b->drm->crtc_list, link)
drm_crtc_destroy(crtc);
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
if (to_drm_head(base))
drm_head_destroy(base);
}
wl_list_for_each_safe(writeback, writeback_tmp,
&b->drm->writeback_connector_list, link)
drm_writeback_destroy(writeback);
#ifdef BUILD_DRM_GBM
if (b->gbm)
gbm_device_destroy(b->gbm);
#endif
udev_monitor_unref(b->udev_monitor);
udev_unref(b->udev);
weston_launcher_close(ec->launcher, device->drm.fd);
weston_launcher_destroy(ec->launcher);
free(device->drm.filename);
free(device);
free(b);
}
static void
session_notify(struct wl_listener *listener, void *data)
{
struct weston_compositor *compositor = data;
struct drm_backend *b =
container_of(listener, struct drm_backend, session_listener);
struct drm_device *device = b->drm;
struct weston_output *output;
if (compositor->session_active) {
weston_log("activating session\n");
weston_compositor_wake(compositor);
weston_compositor_damage_all(compositor);
device->state_invalid = true;
udev_input_enable(&b->input);
} else {
weston_log("deactivating session\n");
udev_input_disable(&b->input);
weston_compositor_offscreen(compositor);
/* If we have a repaint scheduled (either from a
* pending pageflip or the idle handler), make sure we
* cancel that so we don't try to pageflip when we're
* vt switched away. The OFFSCREEN state will prevent
* further attempts at repainting. When we switch
* back, we schedule a repaint, which will process
* pending frame callbacks. */
wl_list_for_each(output, &compositor->output_list, link)
if (to_drm_output(output))
output->repaint_needed = false;
}
}
/**
* Handle KMS GPU being added/removed
*
* If the device being added/removed is the KMS device, we activate/deactivate
* the compositor session.
*
* @param backend The DRM backend instance.
* @param devnum The device being added/removed.
* @param added Whether the device is being added (or removed)
*/
static void
drm_device_changed(struct weston_backend *backend,
dev_t devnum, bool added)
{
struct drm_backend *b = container_of(backend, struct drm_backend, base);
struct weston_compositor *compositor = b->compositor;
struct drm_device *device = b->drm;
if (device->drm.fd < 0 || device->drm.devnum != devnum ||
compositor->session_active == added)
return;
compositor->session_active = added;
wl_signal_emit(&compositor->session_signal, compositor);
}
/**
* Determines whether or not a device is capable of modesetting. If successful,
* sets b->drm.fd and b->drm.filename to the opened device.
*/
static bool
drm_device_is_kms(struct drm_backend *b, struct drm_device *device,
struct udev_device *udev_device)
{
struct weston_compositor *compositor = b->compositor;
const char *filename = udev_device_get_devnode(udev_device);
const char *sysnum = udev_device_get_sysnum(udev_device);
dev_t devnum = udev_device_get_devnum(udev_device);
drmModeRes *res;
int id = -1, fd;
if (!filename)
return false;
fd = weston_launcher_open(compositor->launcher, filename, O_RDWR);
if (fd < 0)
return false;
res = drmModeGetResources(fd);
if (!res)
goto out_fd;
if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
res->count_encoders <= 0)
goto out_res;
if (sysnum)
id = atoi(sysnum);
if (!sysnum || id < 0) {
weston_log("couldn't get sysnum for device %s\n", filename);
goto out_res;
}
/* We can be called successfully on multiple devices; if we have,
* clean up old entries. */
if (device->drm.fd >= 0)
weston_launcher_close(compositor->launcher, device->drm.fd);
free(device->drm.filename);
device->drm.fd = fd;
device->drm.id = id;
device->drm.filename = strdup(filename);
device->drm.devnum = devnum;
drmModeFreeResources(res);
return true;
out_res:
drmModeFreeResources(res);
out_fd:
weston_launcher_close(b->compositor->launcher, fd);
return false;
}
/*
* Find primary GPU
* Some systems may have multiple DRM devices attached to a single seat. This
* function loops over all devices and tries to find a PCI device with the
* boot_vga sysfs attribute set to 1.
* If no such device is found, the first DRM device reported by udev is used.
* Devices are also vetted to make sure they are are capable of modesetting,
* rather than pure render nodes (GPU with no display), or pure
* memory-allocation devices (VGEM).
*/
static struct udev_device*
find_primary_gpu(struct drm_backend *b, const char *seat)
{
struct drm_device *device = b->drm;
struct udev_enumerate *e;
struct udev_list_entry *entry;
const char *path, *device_seat, *id;
struct udev_device *dev, *drm_device, *pci;
e = udev_enumerate_new(b->udev);
udev_enumerate_add_match_subsystem(e, "drm");
udev_enumerate_add_match_sysname(e, "card[0-9]*");
udev_enumerate_scan_devices(e);
drm_device = NULL;
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
bool is_boot_vga = false;
path = udev_list_entry_get_name(entry);
dev = udev_device_new_from_syspath(b->udev, path);
if (!dev)
continue;
device_seat = udev_device_get_property_value(dev, "ID_SEAT");
if (!device_seat)
device_seat = default_seat;
if (strcmp(device_seat, seat)) {
udev_device_unref(dev);
continue;
}
pci = udev_device_get_parent_with_subsystem_devtype(dev,
"pci", NULL);
if (pci) {
id = udev_device_get_sysattr_value(pci, "boot_vga");
if (id && !strcmp(id, "1"))
is_boot_vga = true;
}
/* If we already have a modesetting-capable device, and this
* device isn't our boot-VGA device, we aren't going to use
* it. */
if (!is_boot_vga && drm_device) {
udev_device_unref(dev);
continue;
}
/* Make sure this device is actually capable of modesetting;
* if this call succeeds, device->drm.{fd,filename} will be set,
* and any old values freed. */
if (!drm_device_is_kms(b, b->drm, dev)) {
udev_device_unref(dev);
continue;
}
/* There can only be one boot_vga device, and we try to use it
* at all costs. */
if (is_boot_vga) {
if (drm_device)
udev_device_unref(drm_device);
drm_device = dev;
break;
}
/* Per the (!is_boot_vga && drm_device) test above, we only
* trump existing saved devices with boot-VGA devices, so if
* we end up here, this must be the first device we've seen. */
assert(!drm_device);
drm_device = dev;
}
/* If we're returning a device to use, we must have an open FD for
* it. */
assert(!!drm_device == (device->drm.fd >= 0));
udev_enumerate_unref(e);
return drm_device;
}
static struct udev_device *
open_specific_drm_device(struct drm_backend *b, struct drm_device *device,
const char *name)
{
struct udev_device *udev_device;
udev_device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
if (!udev_device) {
weston_log("ERROR: could not open DRM device '%s'\n", name);
return NULL;
}
if (!drm_device_is_kms(b, device, udev_device)) {
udev_device_unref(udev_device);
weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
return NULL;
}
/* If we're returning a device to use, we must have an open FD for
* it. */
assert(device->drm.fd >= 0);
return udev_device;
}
static void
planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
uint32_t key, void *data)
{
struct drm_backend *b = data;
struct drm_device *device = b->drm;
switch (key) {
case KEY_C:
device->cursors_are_broken ^= true;
break;
case KEY_V:
/* We don't support overlay-plane usage with legacy KMS. */
if (device->atomic_modeset)
device->sprites_are_broken ^= true;
break;
default:
break;
}
}
#ifdef BUILD_VAAPI_RECORDER
static void
recorder_destroy(struct drm_output *output)
{
vaapi_recorder_destroy(output->recorder);
output->recorder = NULL;
weston_output_disable_planes_decr(&output->base);
wl_list_remove(&output->recorder_frame_listener.link);
weston_log("[libva recorder] done\n");
}
static void
recorder_frame_notify(struct wl_listener *listener, void *data)
{
struct drm_output *output;
struct drm_device *device;
int fd, ret;
output = container_of(listener, struct drm_output,
recorder_frame_listener);
device = output->device;
if (!output->recorder)
return;
ret = drmPrimeHandleToFD(device->drm.fd,
output->scanout_plane->state_cur->fb->handles[0],
DRM_CLOEXEC, &fd);
if (ret) {
weston_log("[libva recorder] "
"failed to create prime fd for front buffer\n");
return;
}
ret = vaapi_recorder_frame(output->recorder, fd,
output->scanout_plane->state_cur->fb->strides[0]);
if (ret < 0) {
weston_log("[libva recorder] aborted: %s\n", strerror(errno));
recorder_destroy(output);
}
}
static void *
create_recorder(struct drm_backend *b, int width, int height,
const char *filename)
{
struct drm_device *device = b->drm;
int fd;
drm_magic_t magic;
fd = open(device->drm.filename, O_RDWR | O_CLOEXEC);
if (fd < 0)
return NULL;
drmGetMagic(fd, &magic);
drmAuthMagic(device->drm.fd, magic);
return vaapi_recorder_create(fd, width, height, filename);
}
static void
recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
uint32_t key, void *data)
{
struct drm_backend *b = data;
struct weston_output *base_output;
struct drm_output *output;
int width, height;
wl_list_for_each(base_output, &b->compositor->output_list, link) {
output = to_drm_output(base_output);
if (output)
break;
}
if (!output->recorder) {
if (!output->format ||
output->format->format != DRM_FORMAT_XRGB8888) {
weston_log("failed to start vaapi recorder: "
"output format not supported\n");
return;
}
width = output->base.current_mode->width;
height = output->base.current_mode->height;
output->recorder =
create_recorder(b, width, height, "capture.h264");
if (!output->recorder) {
weston_log("failed to create vaapi recorder\n");
return;
}
weston_output_disable_planes_incr(&output->base);
output->recorder_frame_listener.notify = recorder_frame_notify;
wl_signal_add(&output->base.frame_signal,
&output->recorder_frame_listener);
weston_output_schedule_repaint(&output->base);
weston_log("[libva recorder] initialized\n");
} else {
recorder_destroy(output);
}
}
#else
static void
recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
uint32_t key, void *data)
{
weston_log("Compiled without libva support\n");
}
#endif
static struct drm_device *
drm_device_create(struct drm_backend *backend, const char *name)
{
struct weston_compositor *compositor = backend->compositor;
struct udev_device *udev_device;
struct drm_device *device;
struct wl_event_loop *loop;
drmModeRes *res;
device = zalloc(sizeof *device);
if (device == NULL)
return NULL;
device->state_invalid = true;
device->drm.fd = -1;
device->backend = backend;
device->gem_handle_refcnt = hash_table_create();
udev_device = open_specific_drm_device(backend, device, name);
if (!udev_device) {
free(device);
return NULL;
}
if (init_kms_caps(device) < 0) {
weston_log("failed to initialize kms\n");
goto err;
}
res = drmModeGetResources(device->drm.fd);
if (!res) {
weston_log("Failed to get drmModeRes\n");
goto err;
}
wl_list_init(&device->crtc_list);
if (drm_backend_create_crtc_list(device, res) == -1) {
weston_log("Failed to create CRTC list for DRM-backend\n");
goto err;
}
loop = wl_display_get_event_loop(compositor->wl_display);
wl_event_loop_add_fd(loop, device->drm.fd,
WL_EVENT_READABLE, on_drm_input, device);
wl_list_init(&device->plane_list);
create_sprites(device);
wl_list_init(&device->writeback_connector_list);
if (drm_backend_discover_connectors(device, udev_device, res) < 0) {
weston_log("Failed to create heads for %s\n", device->drm.filename);
goto err;
}
/* 'compute' faked zpos values in case HW doesn't expose any */
drm_backend_create_faked_zpos(device);
return device;
err:
return NULL;
}
static void
open_additional_devices(struct drm_backend *backend, const char *cards)
{
struct drm_device *device;
char *tokenize = strdup(cards);
char *card = strtok(tokenize, ",");
while (card) {
device = drm_device_create(backend, card);
if (!device) {
weston_log("unable to use card %s\n", card);
goto next;
}
weston_log("adding secondary device %s\n",
device->drm.filename);
wl_list_insert(&backend->kms_list, &device->link);
next:
card = strtok(NULL, ",");
}
free(tokenize);
}
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
static const struct weston_drm_output_api api = {
drm_output_set_mode,
drm_output_set_gbm_format,
drm_output_set_seat,
drm_output_set_max_bpc,
drm_output_set_content_type,
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
};
static struct drm_backend *
drm_backend_create(struct weston_compositor *compositor,
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
struct weston_drm_backend_config *config)
{
struct drm_backend *b;
struct drm_device *device;
struct udev_device *drm_device;
struct wl_event_loop *loop;
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
const char *seat_id = default_seat;
const char *session_seat;
backend-drm: add KMS plane's formats to per-surface dma-buf feedback In commit "libweston: add initial dma-buf feedback implementation" we've added initial support to dma-buf feedback, but it was not using the feedback from DRM-backend to add useful per-surface feedback. In this patch we add this. The scanout tranche of the per-surface feedback is based on the union of formats/modifiers of the primary and overlay planes available. These are intersected with the formats/modifiers supported by the renderer device. Also, it's important to mention that the scene can change a lot and we can't predict much. So this patch also adds hysteresis to the dma-buf feedback. We wait a few seconds to be sure that we reached stability before adding or removing the scanout tranche from dma-buf feedback and resending them. This help us to avoid spamming clients and leading to unnecessary buffer reallocations on their end. Here's an example of what we want to avoid: 1. We detect that a view was not placed in a plane only because its format is not supported by the plane, so we add the scanout tranche to the feedback and send the events. 2. A few milliseconds after, the view gets occluded. So now the view can't be placed in a plane anymore. We need to remove the scanout tranche and resend the feedback with formats/modifiers optimal for the renderer device. The client will then reallocate its buffers. 3. A few milliseconds after, the view that was causing the occlusion gets minimized. So we got back to the first situation, in which the format of the view is not compatible with the plane. Then we need to add a scanout tranche and resend the feedback... This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2021-10-12 17:48:36 +00:00
struct weston_drm_format_array *scanout_formats;
drmModeRes *res;
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
int ret;
session_seat = getenv("XDG_SEAT");
if (session_seat)
seat_id = session_seat;
if (config->seat_id)
seat_id = config->seat_id;
weston_log("initializing drm backend\n");
b = zalloc(sizeof *b);
if (b == NULL)
return NULL;
device = zalloc(sizeof *device);
if (device == NULL)
return NULL;
device->state_invalid = true;
device->drm.fd = -1;
device->backend = b;
b->drm = device;
wl_list_init(&b->kms_list);
b->compositor = compositor;
compositor-drm: pageflip timeout implementation Weston will not repaint until previous update has been acked by a pageflip event coming from the drm driver. However, some buggy drivers won’t return those events or will stop sending them at some point and Weston output repaints will completely freeze. To ease developers’ task in testing their drivers, this patch makes compositor-drm use a timer to detect cases where those pageflip events stop coming. This timeout implementation is software only and includes basic features usually found in a watchdog. We simply exit Weston gracefully with a log message and an exit code when the timout is reached. The timeout value can be set via weston.ini by adding a pageflip-timeout=<MILLISECONDS> entry under [core] section. Setting it to 0 disables the timeout feature. v2: - Made sure we would get both the pageflip and the vblank events before stopping the timer. - Reordered the error and success cases in drm_output_pageflip_timer_create() to be more in line with the rest of the code. v3: - Reordered (de)arming of the timer with the code around it to avoid it being rearmed before the current dearming. - Return the proper value for the dispatcher in the pageflip_timeout callback. - Also display the output name in case the timer fires. v4: - Reordered a forgotten timer rearming after its drmModePageFlip(). Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=83884 Signed-off-by: Frederic Plourde <frederic.plourde at collabora.co.uk> Signed-off-by: Emmanuel Gil Peyrot <emmanuel.peyrot@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2017-03-07 13:27:54 +00:00
b->pageflip_timeout = config->pageflip_timeout;
b->use_pixman_shadow = config->use_pixman_shadow;
b->debug = weston_compositor_add_log_scope(compositor, "drm-backend",
"Debug messages from DRM/KMS backend\n",
NULL, NULL, NULL);
wl_list_insert(&compositor->backend_list, &b->base.link);
if (parse_gbm_format(config->gbm_format,
pixel_format_get_info(DRM_FORMAT_XRGB8888),
&b->format) < 0)
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
goto err_compositor;
/* Check if we run drm-backend using a compatible launcher */
compositor->launcher = weston_launcher_connect(compositor, seat_id, true);
if (compositor->launcher == NULL) {
weston_log("fatal: your system should either provide the "
"logind D-Bus API, or use seatd.\n");
goto err_compositor;
}
b->udev = udev_new();
if (b->udev == NULL) {
2012-06-07 16:01:59 +00:00
weston_log("failed to initialize udev context\n");
goto err_launcher;
}
b->session_listener.notify = session_notify;
wl_signal_add(&compositor->session_signal, &b->session_listener);
if (config->specific_device)
drm_device = open_specific_drm_device(b, device,
config->specific_device);
else
drm_device = find_primary_gpu(b, seat_id);
if (drm_device == NULL) {
2012-06-07 16:01:59 +00:00
weston_log("no drm device found\n");
goto err_udev;
}
if (init_kms_caps(device) < 0) {
weston_log("failed to initialize kms\n");
goto err_udev_dev;
}
if (config->additional_devices)
open_additional_devices(b, config->additional_devices);
if (config->renderer == WESTON_RENDERER_AUTO) {
#ifdef BUILD_DRM_GBM
config->renderer = WESTON_RENDERER_GL;
#else
config->renderer = WESTON_RENDERER_PIXMAN;
#endif
}
switch (config->renderer) {
case WESTON_RENDERER_PIXMAN:
if (init_pixman(b) < 0) {
weston_log("failed to initialize pixman renderer\n");
goto err_udev_dev;
}
break;
case WESTON_RENDERER_GL:
if (init_egl(b) < 0) {
weston_log("failed to initialize egl\n");
goto err_udev_dev;
}
break;
default:
weston_log("unsupported renderer for DRM backend\n");
goto err_udev_dev;
}
b->base.shutdown = drm_shutdown;
b->base.destroy = drm_destroy;
b->base.repaint_begin = drm_repaint_begin;
b->base.repaint_flush = drm_repaint_flush;
b->base.repaint_cancel = drm_repaint_cancel;
b->base.create_output = drm_output_create;
b->base.device_changed = drm_device_changed;
b->base.can_scanout_dmabuf = drm_can_scanout_dmabuf;
weston_setup_vt_switch_bindings(compositor);
2012-04-10 04:11:50 +00:00
res = drmModeGetResources(b->drm->drm.fd);
if (!res) {
weston_log("Failed to get drmModeRes\n");
goto err_udev_dev;
}
wl_list_init(&b->drm->crtc_list);
if (drm_backend_create_crtc_list(b->drm, res) == -1) {
weston_log("Failed to create CRTC list for DRM-backend\n");
goto err_create_crtc_list;
}
wl_list_init(&device->plane_list);
create_sprites(b->drm);
if (udev_input_init(&b->input,
compositor, b->udev, seat_id,
config->configure_device) < 0) {
weston_log("failed to create input devices\n");
goto err_sprite;
}
wl_list_init(&b->drm->writeback_connector_list);
if (drm_backend_discover_connectors(b->drm, drm_device, res) < 0) {
weston_log("Failed to create heads for %s\n", b->drm->drm.filename);
goto err_udev_input;
}
drmModeFreeResources(res);
/* 'compute' faked zpos values in case HW doesn't expose any */
drm_backend_create_faked_zpos(b->drm);
/* A this point we have some idea of whether or not we have a working
* cursor plane. */
if (!device->cursors_are_broken)
compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
loop = wl_display_get_event_loop(compositor->wl_display);
b->drm_source =
wl_event_loop_add_fd(loop, b->drm->drm.fd,
WL_EVENT_READABLE, on_drm_input, b->drm);
b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
if (b->udev_monitor == NULL) {
weston_log("failed to initialize udev monitor\n");
goto err_drm_source;
}
udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
"drm", NULL);
b->udev_drm_source =
wl_event_loop_add_fd(loop,
udev_monitor_get_fd(b->udev_monitor),
WL_EVENT_READABLE, udev_drm_event, b);
if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
2012-06-07 16:01:59 +00:00
weston_log("failed to enable udev-monitor receiving\n");
goto err_udev_monitor;
}
udev_device_unref(drm_device);
weston_compositor_add_debug_binding(compositor, KEY_O,
planes_binding, b);
weston_compositor_add_debug_binding(compositor, KEY_C,
planes_binding, b);
weston_compositor_add_debug_binding(compositor, KEY_V,
planes_binding, b);
weston_compositor_add_debug_binding(compositor, KEY_Q,
recorder_binding, b);
if (compositor->renderer->import_dmabuf) {
if (linux_dmabuf_setup(compositor) < 0)
weston_log("Error: initializing dmabuf "
"support failed.\n");
backend-drm: add KMS plane's formats to per-surface dma-buf feedback In commit "libweston: add initial dma-buf feedback implementation" we've added initial support to dma-buf feedback, but it was not using the feedback from DRM-backend to add useful per-surface feedback. In this patch we add this. The scanout tranche of the per-surface feedback is based on the union of formats/modifiers of the primary and overlay planes available. These are intersected with the formats/modifiers supported by the renderer device. Also, it's important to mention that the scene can change a lot and we can't predict much. So this patch also adds hysteresis to the dma-buf feedback. We wait a few seconds to be sure that we reached stability before adding or removing the scanout tranche from dma-buf feedback and resending them. This help us to avoid spamming clients and leading to unnecessary buffer reallocations on their end. Here's an example of what we want to avoid: 1. We detect that a view was not placed in a plane only because its format is not supported by the plane, so we add the scanout tranche to the feedback and send the events. 2. A few milliseconds after, the view gets occluded. So now the view can't be placed in a plane anymore. We need to remove the scanout tranche and resend the feedback with formats/modifiers optimal for the renderer device. The client will then reallocate its buffers. 3. A few milliseconds after, the view that was causing the occlusion gets minimized. So we got back to the first situation, in which the format of the view is not compatible with the plane. Then we need to add a scanout tranche and resend the feedback... This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2021-10-12 17:48:36 +00:00
if (compositor->default_dmabuf_feedback) {
/* We were able to create the compositor's default
* dma-buf feedback in the renderer, that means that the
* table was already created and populated with
* renderer's format/modifier pairs. So now we must
* compute the scanout formats indices in the table */
scanout_formats = get_scanout_formats(b->drm);
backend-drm: add KMS plane's formats to per-surface dma-buf feedback In commit "libweston: add initial dma-buf feedback implementation" we've added initial support to dma-buf feedback, but it was not using the feedback from DRM-backend to add useful per-surface feedback. In this patch we add this. The scanout tranche of the per-surface feedback is based on the union of formats/modifiers of the primary and overlay planes available. These are intersected with the formats/modifiers supported by the renderer device. Also, it's important to mention that the scene can change a lot and we can't predict much. So this patch also adds hysteresis to the dma-buf feedback. We wait a few seconds to be sure that we reached stability before adding or removing the scanout tranche from dma-buf feedback and resending them. This help us to avoid spamming clients and leading to unnecessary buffer reallocations on their end. Here's an example of what we want to avoid: 1. We detect that a view was not placed in a plane only because its format is not supported by the plane, so we add the scanout tranche to the feedback and send the events. 2. A few milliseconds after, the view gets occluded. So now the view can't be placed in a plane anymore. We need to remove the scanout tranche and resend the feedback with formats/modifiers optimal for the renderer device. The client will then reallocate its buffers. 3. A few milliseconds after, the view that was causing the occlusion gets minimized. So we got back to the first situation, in which the format of the view is not compatible with the plane. Then we need to add a scanout tranche and resend the feedback... This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2021-10-12 17:48:36 +00:00
if (!scanout_formats)
goto err_udev_monitor;
ret = weston_dmabuf_feedback_format_table_set_scanout_indices(compositor->dmabuf_feedback_format_table,
scanout_formats);
weston_drm_format_array_fini(scanout_formats);
free(scanout_formats);
backend-drm: add KMS plane's formats to per-surface dma-buf feedback In commit "libweston: add initial dma-buf feedback implementation" we've added initial support to dma-buf feedback, but it was not using the feedback from DRM-backend to add useful per-surface feedback. In this patch we add this. The scanout tranche of the per-surface feedback is based on the union of formats/modifiers of the primary and overlay planes available. These are intersected with the formats/modifiers supported by the renderer device. Also, it's important to mention that the scene can change a lot and we can't predict much. So this patch also adds hysteresis to the dma-buf feedback. We wait a few seconds to be sure that we reached stability before adding or removing the scanout tranche from dma-buf feedback and resending them. This help us to avoid spamming clients and leading to unnecessary buffer reallocations on their end. Here's an example of what we want to avoid: 1. We detect that a view was not placed in a plane only because its format is not supported by the plane, so we add the scanout tranche to the feedback and send the events. 2. A few milliseconds after, the view gets occluded. So now the view can't be placed in a plane anymore. We need to remove the scanout tranche and resend the feedback with formats/modifiers optimal for the renderer device. The client will then reallocate its buffers. 3. A few milliseconds after, the view that was causing the occlusion gets minimized. So we got back to the first situation, in which the format of the view is not compatible with the plane. Then we need to add a scanout tranche and resend the feedback... This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com>
2021-10-12 17:48:36 +00:00
if (ret < 0)
goto err_udev_monitor;
}
if (weston_direct_display_setup(compositor) < 0)
weston_log("Error: initializing direct-display "
"support failed.\n");
}
libweston: Support zwp_surface_synchronization_v1.set_acquire_fence Implement the set_acquire_fence request of the zwp_surface_synchronization_v1 interface. The implementation uses the acquire fence in two ways: 1. If the associated buffer is used as GL render source, an EGLSyncKHR is created from the fence and used to synchronize access. 2. If the associated buffer is used as a plane framebuffer, the acquire fence is treated as an in-fence for the atomic commit operation. If in-fences are not supported and the buffer has an acquire fence, we don't consider it for plane placement. If the used compositor/renderer doesn't support explicit synchronization, we don't advertise the protocol at all. Currently only the DRM and X11 backends when using the GL renderer advertise the protocol for production use. Issues for discussion --------------------- a. Currently, a server-side wait of EGLSyncKHR is performed before using the EGLImage/texture during rendering. Unfortunately, it's not clear from the specs whether this is generally safe to do, or we need to sync before glEGLImageTargetTexture2DOES. The exception is TEXTURE_EXTERNAL_OES where the spec mentions it's enough to sync and then glBindTexture for any changes to take effect. Changes in v5: - Meson support. - Make explicit sync server error reporting more generic, supporting all explicit sync related interfaces not just wp_linux_surface_synchronization. - Fix typo in warning for missing EGL_KHR_wait_sync extension. - Support minor version 2 of the explicit sync protocol (i.e., support fences for opaque EGL buffers). Changes in v4: - Introduce and use fd_clear and and fd_move helpers. - Don't check for a valid buffer when updating surface acquire fence fd from state. - Assert that pending state acquire fence fd is always clear after a commit. - Clarify that WESTON_CAP_EXPLICIT_SYNC applies to just the renderer. - Check for EGL_KHR_wait_sync before using eglWaitSyncKHR. - Dup the acquire fence before passing to EGL. Changes in v3: - Keep acquire_fence_fd in surface instead of buffer. - Clarify that WESTON_CAP_EXPLICIT_SYNC applies to both backend and renderer. - Move comment about non-ownership of in_fence_fd to struct drm_plane_state definition. - Assert that we don't try to use planes with in-fences when using the legacy KMS API. - Remove unnecessary info from wayland error messages. - Handle acquire fence for subsurface commits. - Guard against self-update in fd_update. - Disconnect the client if acquire fence EGLSyncKHR creation or wait fails. - Use updated protocol interface names. - User correct format specifier for resource ids. - Advertise protocol for X11 backend with GL renderer. Changes in v2: - Remove sync file wait fallbacks. - Raise UNSUPPORTED_BUFFER error at commit if we have an acquire fence, but the committed buffer is not a valid linux_dmabuf. - Don't put buffers with in-fences on planes that don't support in-fences. - Don't advertise explicit sync protocol if backend does not support explicit sync. Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
2018-10-19 09:14:11 +00:00
if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
if (linux_explicit_synchronization_setup(compositor) < 0)
weston_log("Error: initializing explicit "
" synchronization support failed.\n");
}
if (device->atomic_modeset)
backend-drm: Add support for content-protection Currently drm-layer supports HDCP1.4 using connector property: Content Protection. This property if available for a platform, can be read and set for requesting content-protection. Also, the patch series [1] adds HDCP2.2 support in drm, and patch [2] adds support to send udev events for change in connector properties, made by the kernel. This patch adds these HDCP connector properties in weston, and exposes the content-protection support to the client for drm-backend. It adds the enums to represent 'Content Protection' and 'Content Type' connector properties exposed by drm layer. It adds a member 'protection' in drm_output_state, to store the desired protection from the weston_output in the drm-backend output-repaint cycle. This is then used to write the HDCP connector properties for the drm_heads attached to the drm_output. The kernel sends uevents to the user-space for any change made by it in the "Content Protection" connector property. No event is sent in case of change in the property made by the user-space. It means, when there is a change of the property value from "DESIRED" to "ENABLE" i.e. successful authentication by the kernel, a uevent will be generated, but in case of userspace requesting for disabling the protection by writing "UNDESIRED" into the property, no uevent will be generated. This patch also adds support for handling new udev events for HDCP connector property changes. Any such change, triggers change in the weston_head's current_protection. [1] https://patchwork.freedesktop.org/series/57233/#rev7 [2] https://patchwork.freedesktop.org/patch/303903/?series=57233&rev=7 Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
2019-05-14 13:06:08 +00:00
if (weston_compositor_enable_content_protection(compositor) < 0)
weston_log("Error: initializing content-protection "
"support failed.\n");
weston: Port DRM backend to new output handling API This is a complete port of the DRM backend that uses the recently added output handling API for output configuration. Output can be configured at runtime by passing the necessary configuration parameters, which can be filled in manually or obtained from the configuration file using previously added functionality. It is required that the scale and transform values are set using the previously added functionality. After everything has been set, output needs to be enabled manually using weston_output_enable(). v2: - Added missing drmModeFreeCrtc() to drm_output_enable() cleanup list in case of failure. - Split drm_backend_disable() into drm_backend_deinit() to accomodate for changes in the first patch in the series. Moved restoring original crtc to drm_output_destroy(). v3: - Moved origcrtc allocation to drm_output_set_mode(). - Swapped connector_get_current_mode() and drm_output_add_mode() calls in drm_output_set_mode() to match current weston. - Moved crtc_allocator and connector_allocator update from drm_output_enable() to create_output_for_connector() to avoid problems when more than one monitor is connected at startup and crtc allocator wasn't updated before create_output_for_connector() was called second time, resulting in one screen being turned off. - Moved crtc_allocator and connector_allocator update from drm_output_deinit() to drm_output_destroy(), as it should not be called on drm_output_disable(). - Use weston_compositor_add_pending_output(). - Bump weston_drm_backend_config version to 2. v4: - Reset output->original_crtc to NULL if drm_output_set_mode() fails. - Remove unneeded log message when disabling an output when a pageflip is pending. - Document that create_output_for_connector() takes ownership of the connector. - Free the connector if create output conditionals are not met in create_outputs() and update_outputs(). Signed-off-by: Armin Krezović <krezovic.armin@gmail.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-09-30 12:11:05 +00:00
ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
&api, sizeof(api));
if (ret < 0) {
weston_log("Failed to register output API.\n");
goto err_udev_monitor;
}
ret = drm_backend_init_virtual_output_api(compositor);
if (ret < 0) {
weston_log("Failed to register virtual output API.\n");
goto err_udev_monitor;
}
return b;
err_udev_monitor:
wl_event_source_remove(b->udev_drm_source);
udev_monitor_unref(b->udev_monitor);
err_drm_source:
wl_event_source_remove(b->drm_source);
err_udev_input:
udev_input_destroy(&b->input);
err_sprite:
destroy_sprites(b->drm);
err_create_crtc_list:
drmModeFreeResources(res);
err_udev_dev:
udev_device_unref(drm_device);
err_udev:
udev_unref(b->udev);
err_launcher:
weston_launcher_destroy(compositor->launcher);
err_compositor:
wl_list_remove(&b->base.link);
#ifdef BUILD_DRM_GBM
if (b->gbm)
gbm_device_destroy(b->gbm);
#endif
free(b);
return NULL;
}
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
static void
config_init_to_defaults(struct weston_drm_backend_config *config)
{
config->renderer = WESTON_RENDERER_AUTO;
config->use_pixman_shadow = true;
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
}
WL_EXPORT int
weston_backend_init(struct weston_compositor *compositor,
struct weston_backend_config *config_base)
{
struct drm_backend *b;
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
struct weston_drm_backend_config config = {{ 0, }};
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
if (config_base == NULL ||
config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
weston_log("drm backend config structure is invalid\n");
return -1;
}
if (compositor->renderer) {
weston_log("drm backend must be the primary backend\n");
return -1;
}
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
b = drm_backend_create(compositor, &config);
if (b == NULL)
return -1;
drm: port the drm backend to the new init api Preparing for libweston and for the separation of the code base into libweston vs. weston the compositor, we must remove all uses weston_config structures from the backends. We have decided that all option and config input happens in the compositor (main.c), and configuration is passed in for the backends as structs. Most other backends have already converted, and this patch converts the DRM-backend to the libweston-style init API. The libweston-style init API includes a header for each backend (here compositor-drm.h) defining the configuration interface. The compositor (main.c) prepares a configuration struct to be passed through libweston core to the backend during initialization. A complication with the DRM-backend is that outputs can be hotplugged, and their configuration needs to be fetched from the compositor (main.c). For this, the config struct contains a callback member. The output configuration API is subject to change later, this is just a temporary API to get libweston forward. As weston_compositor's user_data was not previously used for anything, and the output configuration callback needs data, the user_data is set to the 'config' pointer. This pointer is only used in drm_configure_output() in main.c. [Bryce: lots of stuff and rebasing] Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net> Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Benoit Gschwind <gschwind@gnu-log.net> [Pekka: write commit message] [Pekka: squash in "drm: Don't hang onto the backend config object post-backend_init" from Bryce Harrington] [Pekka: drop the compositor.h hunk] [Pekka: do not #include inside extern "C"] [Pekka: remove incorrect comment about weston_drm_backend_config ownership.] Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-29 22:40:34 +00:00
return 0;
}