1290 lines
37 KiB
Diff
1290 lines
37 KiB
Diff
From 63d6a9fe6500baa7137a972443789a7c2c283ad2 Mon Sep 17 00:00:00 2001
|
|
From: Jeffy Chen <jeffy.chen@rock-chips.com>
|
|
Date: Tue, 23 Jun 2020 10:05:48 +0800
|
|
Subject: [PATCH 21/98] backend-drm: Support selecting monitors
|
|
|
|
Using these environments:
|
|
|
|
WESTON_DRM_PRIMARY:
|
|
Specify primary connector.
|
|
WESTON_DRM_SINGLE_HEAD:
|
|
Force using single connector.
|
|
WESTON_DRM_HEAD_FALLBACK:
|
|
Fallback to any available connector if none matched.
|
|
WESTON_DRM_HEAD_FALLBACK_ALL:
|
|
Fallback to all available connector if none matched.
|
|
WESTON_DRM_PREFER_EXTERNAL_DUAL:
|
|
Prefer external connectors, and also enable internal ones.
|
|
WESTON_DRM_PREFER_EXTERNAL:
|
|
Prefer external connectors, and disable internal ones if any matched.
|
|
|
|
WESTON_DRM_HEAD_MODE:
|
|
default(match primary->internal->external)
|
|
primary(match primary only)
|
|
internal(match primary->internal)
|
|
external(match primary->external)
|
|
external-dual(match primary->external->internal)
|
|
|
|
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
|
|
---
|
|
desktop-shell/shell.c | 84 +++++--
|
|
frontend/main.c | 22 +-
|
|
include/libweston/config-parser.h | 1 +
|
|
include/libweston/libweston.h | 7 +
|
|
kiosk-shell/kiosk-shell.c | 17 ++
|
|
libweston/backend-drm/drm-internal.h | 21 ++
|
|
libweston/backend-drm/drm.c | 361 +++++++++++++++++++++++----
|
|
libweston/backend-drm/kms.c | 22 +-
|
|
libweston/backend.h | 2 +
|
|
libweston/compositor.c | 84 ++++++-
|
|
10 files changed, 535 insertions(+), 86 deletions(-)
|
|
|
|
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
|
|
index 38ddb4aa6..333218dd0 100644
|
|
--- a/desktop-shell/shell.c
|
|
+++ b/desktop-shell/shell.c
|
|
@@ -104,6 +104,7 @@ struct shell_surface {
|
|
struct weston_surface *wsurface_anim_fade;
|
|
struct weston_view *wview_anim_fade;
|
|
int32_t last_width, last_height;
|
|
+ int32_t committed_width, committed_height;
|
|
|
|
struct desktop_shell *shell;
|
|
|
|
@@ -134,7 +135,7 @@ struct shell_surface {
|
|
bool fullscreen;
|
|
bool maximized;
|
|
bool lowered;
|
|
- } state;
|
|
+ } state, requested;
|
|
|
|
struct {
|
|
bool is_set;
|
|
@@ -267,11 +268,12 @@ set_shsurf_size_maximized_or_fullscreen(struct shell_surface *shsurf,
|
|
{
|
|
int width = 0; int height = 0;
|
|
|
|
+ if (!shsurf->output)
|
|
+ return;
|
|
+
|
|
if (fullscreen_requested) {
|
|
- if (shsurf->output) {
|
|
- width = shsurf->output->width;
|
|
- height = shsurf->output->height;
|
|
- }
|
|
+ width = shsurf->output->width;
|
|
+ height = shsurf->output->height;
|
|
} else if (max_requested) {
|
|
/* take the panels into considerations */
|
|
get_maximized_size(shsurf, &width, &height);
|
|
@@ -279,6 +281,10 @@ set_shsurf_size_maximized_or_fullscreen(struct shell_surface *shsurf,
|
|
|
|
/* (0, 0) means we're back from one of the maximized/fullcreen states */
|
|
weston_desktop_surface_set_size(shsurf->desktop_surface, width, height);
|
|
+
|
|
+ if (shsurf->committed_width != width &&
|
|
+ shsurf->committed_height != height)
|
|
+ shsurf->output->resizing = true;
|
|
}
|
|
|
|
static void
|
|
@@ -1882,7 +1888,8 @@ shell_set_view_fullscreen(struct shell_surface *shsurf)
|
|
|
|
weston_view_move_to_layer(shsurf->view,
|
|
&shsurf->shell->fullscreen_layer.view_list);
|
|
- weston_shell_utils_center_on_output(shsurf->view, shsurf->fullscreen_output);
|
|
+
|
|
+ weston_shell_utils_center_on_output(shsurf->view, shsurf->output);
|
|
|
|
if (!shsurf->fullscreen.black_view) {
|
|
shsurf->fullscreen.black_view =
|
|
@@ -2309,6 +2316,9 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
|
|
bool was_fullscreen;
|
|
bool was_maximized;
|
|
|
|
+ shsurf->committed_width = surface->width;
|
|
+ shsurf->committed_height = surface->height;
|
|
+
|
|
if (!weston_surface_has_content(surface) &&
|
|
weston_surface_is_unmapping(surface) &&
|
|
shsurf->state.fullscreen) {
|
|
@@ -2427,6 +2437,7 @@ set_fullscreen(struct shell_surface *shsurf, bool fullscreen,
|
|
struct weston_surface *surface =
|
|
weston_desktop_surface_get_surface(shsurf->desktop_surface);
|
|
|
|
+ shsurf->requested.fullscreen = fullscreen;
|
|
weston_desktop_surface_set_fullscreen(desktop_surface, fullscreen);
|
|
if (fullscreen) {
|
|
/* handle clients launching in fullscreen */
|
|
@@ -2591,6 +2602,7 @@ set_maximized(struct shell_surface *shsurf, bool maximized)
|
|
weston_desktop_surface_set_orientation(shsurf->desktop_surface,
|
|
WESTON_TOP_LEVEL_TILED_ORIENTATION_NONE);
|
|
}
|
|
+ shsurf->requested.maximized = maximized;
|
|
weston_desktop_surface_set_maximized(desktop_surface, maximized);
|
|
set_shsurf_size_maximized_or_fullscreen(shsurf, maximized, false);
|
|
}
|
|
@@ -2786,6 +2798,8 @@ background_committed(struct weston_surface *es,
|
|
weston_surface_map(es);
|
|
assert(wl_list_empty(&es->views));
|
|
sh_output->background_view = weston_view_create(es);
|
|
+ weston_view_set_output(sh_output->background_view,
|
|
+ sh_output->output);
|
|
}
|
|
|
|
assert(sh_output->background_view);
|
|
@@ -2898,6 +2912,8 @@ panel_committed(struct weston_surface *es,
|
|
|
|
weston_view_move_to_layer(sh_output->panel_view,
|
|
&shell->panel_layer.view_list);
|
|
+
|
|
+ weston_view_set_output(sh_output->panel_view, output);
|
|
}
|
|
|
|
assert(sh_output->panel_view);
|
|
@@ -3822,6 +3838,9 @@ shell_fade_done(struct weston_view_animation *animation, void *data)
|
|
{
|
|
struct desktop_shell *shell = data;
|
|
|
|
+ if (!shell->fade.curtain)
|
|
+ return;
|
|
+
|
|
shell->fade.animation = NULL;
|
|
switch (shell->fade.type) {
|
|
case FADE_IN:
|
|
@@ -3876,6 +3895,7 @@ shell_fade_create_view(struct desktop_shell *shell)
|
|
x2 = MAX(x2, op->pos.c.x + op->width);
|
|
y2 = MAX(y2, op->pos.c.y + op->height);
|
|
}
|
|
+
|
|
curtain_params.pos.c.x = x1;
|
|
curtain_params.pos.c.y = y1;
|
|
curtain_params.width = x2 - x1;
|
|
@@ -4507,6 +4527,9 @@ shell_reposition_view_on_output_change(struct weston_view *view)
|
|
if (!shsurf)
|
|
return;
|
|
|
|
+ if (shsurf->fullscreen_output && shsurf->fullscreen_output->destroying)
|
|
+ shsurf->fullscreen_output = NULL;
|
|
+
|
|
if (!visible) {
|
|
struct weston_coord_global pos;
|
|
|
|
@@ -4520,16 +4543,7 @@ shell_reposition_view_on_output_change(struct weston_view *view)
|
|
weston_view_set_position(view, pos);
|
|
} else {
|
|
weston_view_geometry_dirty(view);
|
|
-
|
|
- if (shsurf->state.maximized ||
|
|
- shsurf->state.fullscreen)
|
|
- return;
|
|
}
|
|
-
|
|
-
|
|
- shsurf->saved_position_valid = false;
|
|
- set_maximized(shsurf, false);
|
|
- set_fullscreen(shsurf, false, NULL);
|
|
}
|
|
|
|
void
|
|
@@ -4599,16 +4613,18 @@ static void
|
|
handle_output_resized_shsurfs(struct desktop_shell *shell)
|
|
{
|
|
struct shell_surface *shsurf;
|
|
+ struct shell_output *shell_output;
|
|
+
|
|
+ wl_list_for_each(shell_output, &shell->output_list, link)
|
|
+ shell_output->output->resizing = false;
|
|
|
|
wl_list_for_each(shsurf, &shell->shsurf_list, link) {
|
|
struct weston_desktop_surface *dsurface =
|
|
shsurf->desktop_surface;
|
|
|
|
if (dsurface) {
|
|
- bool is_maximized =
|
|
- weston_desktop_surface_get_maximized(dsurface);
|
|
- bool is_fullscreen =
|
|
- weston_desktop_surface_get_fullscreen(dsurface);
|
|
+ bool is_maximized = shsurf->requested.maximized;
|
|
+ bool is_fullscreen = shsurf->requested.fullscreen;
|
|
|
|
if (is_maximized || is_fullscreen) {
|
|
set_shsurf_size_maximized_or_fullscreen(shsurf,
|
|
@@ -4628,6 +4644,10 @@ handle_output_resized(struct wl_listener *listener, void *data)
|
|
struct weston_output *output = (struct weston_output *)data;
|
|
struct shell_output *sh_output = find_shell_output_from_weston_output(shell, output);
|
|
|
|
+ /* HACK: The resized signal might be eariler than the created signal */
|
|
+ if (!sh_output)
|
|
+ return;
|
|
+
|
|
handle_output_resized_shsurfs(shell);
|
|
|
|
shell_resize_surface_to_output(shell, sh_output->background_surface, output);
|
|
@@ -4688,12 +4708,27 @@ handle_output_move_layer(struct desktop_shell *shell,
|
|
static void
|
|
handle_output_move(struct wl_listener *listener, void *data)
|
|
{
|
|
+ struct weston_output *output = data;
|
|
+ struct weston_compositor *compositor = output->compositor;
|
|
struct desktop_shell *shell;
|
|
|
|
shell = container_of(listener, struct desktop_shell,
|
|
output_move_listener);
|
|
|
|
- shell_for_each_layer(shell, handle_output_move_layer, data);
|
|
+ if (shell->lock_surface) {
|
|
+ struct weston_coord_surface offset =
|
|
+ weston_coord_surface(0, 0, shell->lock_surface);
|
|
+ shell->lock_surface->committed(shell->lock_surface, offset);
|
|
+ }
|
|
+
|
|
+ /* Only move normal layers for non-default output */
|
|
+ if (output != weston_shell_utils_get_default_output(compositor)) {
|
|
+ shell_for_each_layer(shell, handle_output_move_layer, data);
|
|
+ } else {
|
|
+ handle_output_move_layer(shell, &shell->lock_layer, data);
|
|
+ handle_output_move_layer(shell, &shell->background_layer, data);
|
|
+ handle_output_move_layer(shell, &shell->panel_layer, data);
|
|
+ }
|
|
}
|
|
|
|
static void
|
|
@@ -4786,8 +4821,11 @@ shell_destroy(struct wl_listener *listener, void *data)
|
|
shell->fade.animation = NULL;
|
|
}
|
|
|
|
- if (shell->fade.curtain)
|
|
- weston_shell_utils_curtain_destroy(shell->fade.curtain);
|
|
+ if (shell->fade.curtain) {
|
|
+ struct weston_curtain *curtain = shell->fade.curtain;
|
|
+ shell->fade.curtain = NULL;
|
|
+ weston_shell_utils_curtain_destroy(curtain);
|
|
+ }
|
|
|
|
if (shell->fade.startup_timer)
|
|
wl_event_source_remove(shell->fade.startup_timer);
|
|
@@ -5032,5 +5070,7 @@ wet_shell_init(struct weston_compositor *ec,
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &shell->startup_time);
|
|
|
|
+ ec->block_output_resizing = true;
|
|
+
|
|
return 0;
|
|
}
|
|
diff --git a/frontend/main.c b/frontend/main.c
|
|
index 3220629e4..f0d12a48c 100644
|
|
--- a/frontend/main.c
|
|
+++ b/frontend/main.c
|
|
@@ -2766,7 +2766,7 @@ drm_head_prepare_enable(struct wet_compositor *wet,
|
|
char *output_name = NULL;
|
|
char *mode = NULL;
|
|
|
|
- section = drm_config_find_controlling_output_section(wet->config, name);
|
|
+ section = head->section;
|
|
if (section) {
|
|
/* skip outputs that are explicitly off, or non-desktop and not
|
|
* explicitly enabled. The backend turns them off automatically.
|
|
@@ -2796,11 +2796,10 @@ static bool
|
|
drm_head_should_force_enable(struct wet_compositor *wet,
|
|
struct weston_head *head)
|
|
{
|
|
- const char *name = weston_head_get_name(head);
|
|
struct weston_config_section *section;
|
|
bool force;
|
|
|
|
- section = drm_config_find_controlling_output_section(wet->config, name);
|
|
+ section = head->section;
|
|
if (!section)
|
|
return false;
|
|
|
|
@@ -2999,6 +2998,21 @@ drm_head_disable(struct weston_head *head)
|
|
wet_output_destroy(output);
|
|
}
|
|
|
|
+static bool
|
|
+drm_head_update_output_section(struct weston_head *head)
|
|
+{
|
|
+ struct weston_compositor *compositor = head->compositor;
|
|
+ struct wet_compositor *wet = to_wet_compositor(compositor);
|
|
+ const char *name = weston_head_get_name(head);
|
|
+
|
|
+ if (head->section)
|
|
+ return true;
|
|
+
|
|
+ head->section =
|
|
+ drm_config_find_controlling_output_section(wet->config, name);
|
|
+ return !!head->section;
|
|
+}
|
|
+
|
|
static void
|
|
drm_heads_changed(struct wl_listener *listener, void *arg)
|
|
{
|
|
@@ -3016,6 +3030,8 @@ drm_heads_changed(struct wl_listener *listener, void *arg)
|
|
* output.
|
|
*/
|
|
while ((head = wet_backend_iterate_heads(wet, wb, head))) {
|
|
+ drm_head_update_output_section(head);
|
|
+
|
|
connected = weston_head_is_connected(head);
|
|
enabled = weston_head_is_enabled(head);
|
|
changed = weston_head_is_device_changed(head);
|
|
diff --git a/include/libweston/config-parser.h b/include/libweston/config-parser.h
|
|
index 8ed14a3b5..e05a90b5b 100644
|
|
--- a/include/libweston/config-parser.h
|
|
+++ b/include/libweston/config-parser.h
|
|
@@ -32,6 +32,7 @@ extern "C" {
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
+#include <stdio.h>
|
|
|
|
#define WESTON_CONFIG_FILE_ENV_VAR "WESTON_CONFIG_FILE"
|
|
|
|
diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h
|
|
index 77b44baa2..be3cbdaaa 100644
|
|
--- a/include/libweston/libweston.h
|
|
+++ b/include/libweston/libweston.h
|
|
@@ -516,6 +516,8 @@ struct weston_head {
|
|
* When a client uses this request, we add the wl_resource we create to
|
|
* this list. */
|
|
struct wl_list cm_output_resource_list;
|
|
+
|
|
+ struct weston_config_section *section; /**< config section **/
|
|
};
|
|
|
|
enum weston_output_power_state {
|
|
@@ -711,6 +713,9 @@ struct weston_output {
|
|
* mirror-of key in [output] section.
|
|
*/
|
|
struct weston_output *mirror_of;
|
|
+
|
|
+ /* Resizing maximized or fullscreen surfaces */
|
|
+ bool resizing;
|
|
};
|
|
|
|
enum weston_pointer_motion_mask {
|
|
@@ -1633,6 +1638,8 @@ struct weston_compositor {
|
|
struct wl_signal ask_auth;
|
|
} output_capture;
|
|
|
|
+ bool block_output_resizing;
|
|
+
|
|
enum weston_output_flow output_flow;
|
|
};
|
|
|
|
diff --git a/kiosk-shell/kiosk-shell.c b/kiosk-shell/kiosk-shell.c
|
|
index 099478d9a..440e36e13 100644
|
|
--- a/kiosk-shell/kiosk-shell.c
|
|
+++ b/kiosk-shell/kiosk-shell.c
|
|
@@ -447,6 +447,10 @@ kiosk_shell_surface_reconfigure_for_output(struct kiosk_shell_surface *shsurf)
|
|
weston_desktop_surface_set_size(desktop_surface,
|
|
shsurf->output->width,
|
|
shsurf->output->height);
|
|
+
|
|
+ if (shsurf->last_width != shsurf->output->width ||
|
|
+ shsurf->last_height != shsurf->output->height)
|
|
+ shsurf->output->resizing = true;
|
|
}
|
|
|
|
weston_shell_utils_center_on_output(shsurf->view, shsurf->output);
|
|
@@ -1072,6 +1076,11 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
|
|
|
|
shsurf->last_width = surface->width;
|
|
shsurf->last_height = surface->height;
|
|
+
|
|
+ if (is_fullscreen && shsurf->output &&
|
|
+ (shsurf->last_width != shsurf->output->width ||
|
|
+ shsurf->last_height != shsurf->output->height))
|
|
+ shsurf->output->resizing = true;
|
|
}
|
|
|
|
static void
|
|
@@ -1337,6 +1346,12 @@ kiosk_shell_handle_output_resized(struct wl_listener *listener, void *data)
|
|
kiosk_shell_find_shell_output(shell, output);
|
|
struct weston_view *view;
|
|
|
|
+ /* HACK: The resized signal might be eariler than the created signal */
|
|
+ if (!shoutput)
|
|
+ return;
|
|
+
|
|
+ output->resizing = false;
|
|
+
|
|
kiosk_shell_output_recreate_background(shoutput);
|
|
|
|
wl_list_for_each(view, &shell->normal_layer.view_list.link,
|
|
@@ -1542,5 +1557,7 @@ wet_shell_init(struct weston_compositor *ec,
|
|
|
|
kiosk_shell_add_bindings(shell);
|
|
|
|
+ ec->block_output_resizing = true;
|
|
+
|
|
return 0;
|
|
}
|
|
diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
|
|
index d00dc6f3b..f8f3d93cb 100644
|
|
--- a/libweston/backend-drm/drm-internal.h
|
|
+++ b/libweston/backend-drm/drm-internal.h
|
|
@@ -116,6 +116,8 @@
|
|
|
|
#define MAX_CLONED_CONNECTORS 4
|
|
|
|
+/* Min duration between drm outputs update requests, to avoid glith */
|
|
+#define DRM_MIN_UPDATE_MS 1000
|
|
|
|
/**
|
|
* Represents the values of an enum-type KMS property
|
|
@@ -188,6 +190,7 @@ struct drm_device {
|
|
int fd;
|
|
char *filename;
|
|
dev_t devnum;
|
|
+ char *syspath;
|
|
} drm;
|
|
|
|
/* Track the GEM handles if the device does not have a gbm device, which
|
|
@@ -234,6 +237,10 @@ struct drm_device {
|
|
struct wl_list link;
|
|
};
|
|
|
|
+struct drm_head;
|
|
+struct drm_backend;
|
|
+typedef bool (*drm_head_match_t) (struct drm_backend *, struct drm_head *);
|
|
+
|
|
struct drm_backend {
|
|
struct weston_backend base;
|
|
struct weston_compositor *compositor;
|
|
@@ -261,6 +268,18 @@ struct drm_backend {
|
|
bool has_underlay;
|
|
|
|
struct weston_log_scope *debug;
|
|
+
|
|
+ struct wl_event_source *hotplug_timer;
|
|
+ bool pending_update;
|
|
+ int64_t last_update_ms;
|
|
+ int64_t resize_freeze_ms;
|
|
+
|
|
+ bool single_head;
|
|
+ bool head_fallback;
|
|
+ bool head_fallback_all;
|
|
+ drm_head_match_t *head_matches;
|
|
+ struct drm_head *primary_head;
|
|
+ struct wl_listener output_create_listener;
|
|
};
|
|
|
|
struct drm_mode {
|
|
@@ -590,6 +609,8 @@ struct drm_output {
|
|
submit_frame_cb virtual_submit_frame;
|
|
|
|
enum wdrm_content_type content_type;
|
|
+
|
|
+ bool state_invalid;
|
|
};
|
|
|
|
void
|
|
diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
|
|
index 360a8657a..4a6e30b0c 100644
|
|
--- a/libweston/backend-drm/drm.c
|
|
+++ b/libweston/backend-drm/drm.c
|
|
@@ -48,6 +48,7 @@
|
|
|
|
#include <libudev.h>
|
|
|
|
+#include <libweston/config-parser.h>
|
|
#include <libweston/libweston.h>
|
|
#include <libweston/backend-drm.h>
|
|
#include <libweston/weston-log.h>
|
|
@@ -71,6 +72,45 @@
|
|
|
|
static const char default_seat[] = "seat0";
|
|
|
|
+static inline bool
|
|
+drm_head_is_external(struct drm_head *head)
|
|
+{
|
|
+ drmModeConnector *conn = head->connector.conn;
|
|
+ switch (conn->connector_type) {
|
|
+ case DRM_MODE_CONNECTOR_LVDS:
|
|
+ case DRM_MODE_CONNECTOR_eDP:
|
|
+#ifdef DRM_MODE_CONNECTOR_DSI
|
|
+ case DRM_MODE_CONNECTOR_DSI:
|
|
+#endif
|
|
+ return false;
|
|
+ default:
|
|
+ return true;
|
|
+ }
|
|
+};
|
|
+
|
|
+static void
|
|
+drm_backend_update_outputs(struct drm_backend *b)
|
|
+{
|
|
+ struct weston_output *primary;
|
|
+
|
|
+ if (!b->primary_head)
|
|
+ return;
|
|
+
|
|
+ primary = b->primary_head->base.output;
|
|
+ if (!primary)
|
|
+ return;
|
|
+
|
|
+ wl_list_remove(&primary->link);
|
|
+ wl_list_insert(&b->compositor->output_list, &primary->link);
|
|
+
|
|
+ weston_compositor_reflow_outputs(b->compositor);
|
|
+ weston_compositor_damage_all(b->compositor);
|
|
+
|
|
+ /* Ensure maximized and fullscreen surfaces resized */
|
|
+ if (b->compositor->block_output_resizing)
|
|
+ primary->resizing = true;
|
|
+}
|
|
+
|
|
static void
|
|
drm_backend_create_faked_zpos(struct drm_device *device)
|
|
{
|
|
@@ -1089,6 +1129,7 @@ drm_output_apply_mode(struct drm_output *output)
|
|
* content.
|
|
*/
|
|
device->state_invalid = true;
|
|
+ output->state_invalid = true;
|
|
|
|
fb_size.width = output->base.current_mode->width;
|
|
fb_size.height = output->base.current_mode->height;
|
|
@@ -1755,6 +1796,7 @@ drm_output_attach_head(struct weston_output *output_base,
|
|
* will not clear the flag before this output is updated?
|
|
*/
|
|
device->state_invalid = true;
|
|
+ output->state_invalid = true;
|
|
|
|
weston_output_schedule_repaint(output_base);
|
|
|
|
@@ -2383,6 +2425,8 @@ drm_output_enable(struct weston_output *base)
|
|
output->base.switch_mode = drm_output_switch_mode;
|
|
output->base.set_gamma = drm_output_set_gamma;
|
|
|
|
+ output->state_invalid = true;
|
|
+
|
|
if (device->atomic_modeset)
|
|
weston_output_update_capture_info(base, WESTON_OUTPUT_CAPTURE_SOURCE_WRITEBACK,
|
|
base->current_mode->width,
|
|
@@ -2776,8 +2820,7 @@ drm_head_create(struct drm_device *device, drmModeConnector *conn,
|
|
head->backlight = NULL;
|
|
}
|
|
|
|
- if (conn->connector_type == DRM_MODE_CONNECTOR_LVDS ||
|
|
- conn->connector_type == DRM_MODE_CONNECTOR_eDP)
|
|
+ if (!drm_head_is_external(head))
|
|
weston_head_set_internal(&head->base);
|
|
|
|
if (drm_head_read_current_setup(head, device) < 0) {
|
|
@@ -3176,56 +3219,54 @@ drm_backend_add_connector(struct drm_device *device, drmModeConnector *conn,
|
|
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)
|
|
+static bool
|
|
+resources_has_connector(drmModeRes *resources, uint32_t connector_id)
|
|
{
|
|
- drmModeConnector *conn;
|
|
- int i, ret;
|
|
+ for (int i = 0; i < resources->count_connectors; i++) {
|
|
+ if (resources->connectors[i] == connector_id)
|
|
+ return true;
|
|
+ }
|
|
|
|
- device->min_width = resources->min_width;
|
|
- device->max_width = resources->max_width;
|
|
- device->min_height = resources->min_height;
|
|
- device->max_height = resources->max_height;
|
|
+ return false;
|
|
+}
|
|
|
|
- for (i = 0; i < resources->count_connectors; i++) {
|
|
- uint32_t connector_id = resources->connectors[i];
|
|
+/* based on frontend/main.c#drm_head_prepare_enable() */
|
|
+static bool
|
|
+drm_head_is_available(struct weston_head *head)
|
|
+{
|
|
+ struct weston_config_section *section;
|
|
+ char *mode = NULL;
|
|
|
|
- conn = drmModeGetConnector(device->drm.fd, connector_id);
|
|
- if (!conn)
|
|
- continue;
|
|
+ section = head->section;
|
|
+ if (!section)
|
|
+ return true;
|
|
|
|
- ret = drm_backend_add_connector(device, conn, drm_device);
|
|
- if (ret < 0)
|
|
- drmModeFreeConnector(conn);
|
|
+ /* skip outputs that are explicitly off, or non-desktop and not
|
|
+ * explicitly enabled.
|
|
+ */
|
|
+ weston_config_section_get_string(section, "mode", &mode, NULL);
|
|
+ if (mode && strcmp(mode, "off") == 0) {
|
|
+ free(mode);
|
|
+ return false;
|
|
}
|
|
|
|
- return 0;
|
|
+ if (!mode && weston_head_is_non_desktop(head))
|
|
+ return false;
|
|
+
|
|
+ free(mode);
|
|
+ return true;
|
|
}
|
|
|
|
static bool
|
|
-resources_has_connector(drmModeRes *resources, uint32_t connector_id)
|
|
+drm_head_match_fallback(struct drm_backend *b, struct drm_head *head)
|
|
{
|
|
- for (int i = 0; i < resources->count_connectors; i++) {
|
|
- if (resources->connectors[i] == connector_id)
|
|
- return true;
|
|
- }
|
|
+ if (b->head_fallback_all)
|
|
+ return true;
|
|
|
|
- return false;
|
|
+ return b->head_fallback && !b->primary_head;
|
|
}
|
|
|
|
-static void
|
|
+static int
|
|
drm_backend_update_connectors(struct drm_device *device,
|
|
struct udev_device *drm_device)
|
|
{
|
|
@@ -3235,15 +3276,22 @@ drm_backend_update_connectors(struct drm_device *device,
|
|
struct weston_head *base, *base_next;
|
|
struct drm_head *head;
|
|
struct drm_writeback *writeback, *writeback_next;
|
|
+ drm_head_match_t *match = b->head_matches;
|
|
+ struct timespec now;
|
|
uint32_t connector_id;
|
|
int i, ret;
|
|
|
|
resources = drmModeGetResources(device->drm.fd);
|
|
if (!resources) {
|
|
weston_log("drmModeGetResources failed\n");
|
|
- return;
|
|
+ return -1;
|
|
}
|
|
|
|
+ device->min_width = resources->min_width;
|
|
+ device->max_width = resources->max_width;
|
|
+ device->min_height = resources->min_height;
|
|
+ device->max_height = resources->max_height;
|
|
+
|
|
/* collect new connectors that have appeared, e.g. MST */
|
|
for (i = 0; i < resources->count_connectors; i++) {
|
|
connector_id = resources->connectors[i];
|
|
@@ -3308,6 +3356,62 @@ drm_backend_update_connectors(struct drm_device *device,
|
|
}
|
|
|
|
drmModeFreeResources(resources);
|
|
+
|
|
+ /* Disconnect drm heads */
|
|
+ wl_list_for_each_safe(base, base_next,
|
|
+ &b->compositor->head_list, compositor_link) {
|
|
+ if (base->backend == &b->base)
|
|
+ weston_head_set_connection_status(base, false);
|
|
+ }
|
|
+
|
|
+ /* Re-connect matched heads and find primary head */
|
|
+ b->primary_head = NULL;
|
|
+ while (*match) {
|
|
+ wl_list_for_each_safe(base, base_next,
|
|
+ &b->compositor->head_list,
|
|
+ compositor_link) {
|
|
+ drmModeConnector *conn;
|
|
+
|
|
+ if (base->backend != &b->base ||
|
|
+ !drm_head_is_available(base))
|
|
+ continue;
|
|
+
|
|
+ head = to_drm_head(base);
|
|
+ conn = head->connector.conn;
|
|
+
|
|
+ if (conn->connection != DRM_MODE_CONNECTED ||
|
|
+ !(*match)(b, head))
|
|
+ continue;
|
|
+
|
|
+ weston_head_set_connection_status(base, true);
|
|
+
|
|
+ if (!b->primary_head) {
|
|
+ b->primary_head = head;
|
|
+
|
|
+ /* Done the single-head match */
|
|
+ if (b->single_head)
|
|
+ goto match_done;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Done the fallback match */
|
|
+ if (*match == drm_head_match_fallback)
|
|
+ goto match_done;
|
|
+
|
|
+ match++;
|
|
+
|
|
+ /* Try the fallback match */
|
|
+ if (!match && !b->primary_head)
|
|
+ *match = drm_head_match_fallback;
|
|
+ }
|
|
+match_done:
|
|
+
|
|
+ drm_backend_update_outputs(b);
|
|
+
|
|
+ weston_compositor_read_presentation_clock(b->compositor, &now);
|
|
+ b->last_update_ms = timespec_to_msec(&now);
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
static enum wdrm_connector_property
|
|
@@ -3399,6 +3503,50 @@ udev_event_is_conn_prop_change(struct drm_backend *b,
|
|
return 1;
|
|
}
|
|
|
|
+static void
|
|
+udev_hotplug_event(struct drm_device *device, struct udev_device *udev_device)
|
|
+{
|
|
+ struct drm_backend *b = device->backend;
|
|
+ struct timespec now;
|
|
+ int64_t now_ms, next_ms;
|
|
+
|
|
+ weston_compositor_read_presentation_clock(b->compositor, &now);
|
|
+ now_ms = timespec_to_msec(&now);
|
|
+
|
|
+ /* Already have a pending request */
|
|
+ if (b->pending_update)
|
|
+ return;
|
|
+
|
|
+ next_ms = b->last_update_ms + DRM_MIN_UPDATE_MS;
|
|
+ if (next_ms <= now_ms) {
|
|
+ /* Long enough to trigger a new request */
|
|
+ drm_backend_update_connectors(device, udev_device);
|
|
+ } else {
|
|
+ /* Too close to the last request, schedule a new one */
|
|
+ b->pending_update = true;
|
|
+ wl_event_source_timer_update(b->hotplug_timer,
|
|
+ next_ms - now_ms);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int
|
|
+hotplug_timer_handler(void *data)
|
|
+{
|
|
+ struct drm_device *device = data;
|
|
+ struct drm_backend *b = device->backend;
|
|
+ struct udev_device *udev_device;
|
|
+ struct udev *udev;
|
|
+
|
|
+ udev = udev_monitor_get_udev(b->udev_monitor);
|
|
+ udev_device = udev_device_new_from_syspath(udev, device->drm.syspath);
|
|
+
|
|
+ drm_backend_update_connectors(device, udev_device);
|
|
+ b->pending_update = false;
|
|
+
|
|
+ udev_device_unref(udev_device);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int
|
|
udev_drm_event(int fd, uint32_t mask, void *data)
|
|
{
|
|
@@ -3413,7 +3561,7 @@ udev_drm_event(int fd, uint32_t mask, void *data)
|
|
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);
|
|
else
|
|
- drm_backend_update_connectors(b->drm, event);
|
|
+ udev_hotplug_event(b->drm, event);
|
|
}
|
|
|
|
wl_list_for_each(device, &b->kms_list, link) {
|
|
@@ -3440,6 +3588,7 @@ drm_shutdown(struct weston_backend *backend)
|
|
|
|
udev_input_destroy(&b->input);
|
|
|
|
+ wl_event_source_remove(b->hotplug_timer);
|
|
wl_event_source_remove(b->udev_drm_source);
|
|
wl_event_source_remove(b->drm_source);
|
|
|
|
@@ -3533,6 +3682,11 @@ session_notify(struct wl_listener *listener, void *data)
|
|
weston_compositor_wake(compositor);
|
|
weston_compositor_damage_all(compositor);
|
|
device->state_invalid = true;
|
|
+
|
|
+ wl_list_for_each(output, &compositor->output_list, link)
|
|
+ if (to_drm_output(output))
|
|
+ to_drm_output(output)->state_invalid = true;
|
|
+
|
|
udev_input_enable(&b->input);
|
|
} else {
|
|
weston_log("deactivating session\n");
|
|
@@ -3939,7 +4093,7 @@ drm_device_create(struct drm_backend *backend, const char *name)
|
|
create_sprites(device, res);
|
|
|
|
wl_list_init(&device->writeback_connector_list);
|
|
- if (drm_backend_discover_connectors(device, udev_device, res) < 0) {
|
|
+ if (drm_backend_update_connectors(device, udev_device) < 0) {
|
|
weston_log("Failed to create heads for %s\n", device->drm.filename);
|
|
goto err;
|
|
}
|
|
@@ -3977,6 +4131,16 @@ next:
|
|
free(tokenize);
|
|
}
|
|
|
|
+static void
|
|
+output_create_notify(struct wl_listener *listener, void *data)
|
|
+{
|
|
+ struct drm_backend *b = container_of(listener, struct drm_backend,
|
|
+ output_create_listener);
|
|
+
|
|
+ /* NOTE: It might trigger output resized signal too early */
|
|
+ drm_backend_update_outputs(b);
|
|
+}
|
|
+
|
|
static const struct weston_drm_output_api api = {
|
|
drm_output_set_mode,
|
|
drm_output_set_gbm_format,
|
|
@@ -3985,6 +4149,70 @@ static const struct weston_drm_output_api api = {
|
|
drm_output_set_content_type,
|
|
};
|
|
|
|
+enum drm_head_mode {
|
|
+ DRM_HEAD_MODE_DEFAULT,
|
|
+ DRM_HEAD_MODE_PRIMARY,
|
|
+ DRM_HEAD_MODE_INTERNAL,
|
|
+ DRM_HEAD_MODE_EXTERNAL,
|
|
+ DRM_HEAD_MODE_EXTERNAL_DUAL,
|
|
+};
|
|
+
|
|
+static bool
|
|
+drm_head_match_primary(struct drm_backend *b, struct drm_head *head)
|
|
+{
|
|
+ const char *buf = getenv("WESTON_DRM_PRIMARY");
|
|
+ return buf && !strcmp(buf, head->base.name);
|
|
+}
|
|
+
|
|
+static bool
|
|
+drm_head_match_external(struct drm_backend *b, struct drm_head *head)
|
|
+{
|
|
+ return drm_head_is_external(head);
|
|
+}
|
|
+
|
|
+static bool
|
|
+drm_head_match_internal(struct drm_backend *b, struct drm_head *head)
|
|
+{
|
|
+ return !drm_head_is_external(head);
|
|
+}
|
|
+
|
|
+#define DRM_HEAD_MAX_MATCHES 5
|
|
+static drm_head_match_t drm_head_matches[][DRM_HEAD_MAX_MATCHES] = {
|
|
+ [DRM_HEAD_MODE_DEFAULT] = {
|
|
+ drm_head_match_primary,
|
|
+ drm_head_match_internal,
|
|
+ drm_head_match_external,
|
|
+ NULL,
|
|
+ },
|
|
+ [DRM_HEAD_MODE_PRIMARY] = {
|
|
+ drm_head_match_primary,
|
|
+ NULL,
|
|
+ },
|
|
+ [DRM_HEAD_MODE_INTERNAL] = {
|
|
+ drm_head_match_primary,
|
|
+ drm_head_match_internal,
|
|
+ NULL,
|
|
+ },
|
|
+ [DRM_HEAD_MODE_EXTERNAL] = {
|
|
+ drm_head_match_primary,
|
|
+ drm_head_match_external,
|
|
+ NULL,
|
|
+ },
|
|
+ [DRM_HEAD_MODE_EXTERNAL_DUAL] = {
|
|
+ drm_head_match_primary,
|
|
+ drm_head_match_external,
|
|
+ drm_head_match_internal,
|
|
+ NULL,
|
|
+ },
|
|
+};
|
|
+
|
|
+static void
|
|
+drm_late_init(struct weston_backend *backend) {
|
|
+ struct drm_backend *b = container_of(backend, struct drm_backend, base);
|
|
+
|
|
+ hotplug_timer_handler(b->drm);
|
|
+}
|
|
+
|
|
static struct drm_backend *
|
|
drm_backend_create(struct weston_compositor *compositor,
|
|
struct weston_drm_backend_config *config)
|
|
@@ -3996,7 +4224,9 @@ drm_backend_create(struct weston_compositor *compositor,
|
|
const char *seat_id = default_seat;
|
|
const char *session_seat;
|
|
struct weston_drm_format_array *scanout_formats;
|
|
+ enum drm_head_mode head_mode = DRM_HEAD_MODE_DEFAULT;
|
|
drmModeRes *res;
|
|
+ char *buf;
|
|
int ret;
|
|
|
|
session_seat = getenv("XDG_SEAT");
|
|
@@ -4012,6 +4242,42 @@ drm_backend_create(struct weston_compositor *compositor,
|
|
if (b == NULL)
|
|
return NULL;
|
|
|
|
+ buf = getenv("WESTON_DRM_SINGLE_HEAD");
|
|
+ if (buf && buf[0] == '1')
|
|
+ b->single_head = true;
|
|
+
|
|
+ buf = getenv("WESTON_DRM_HEAD_FALLBACK");
|
|
+ if (buf && buf[0] == '1')
|
|
+ b->head_fallback = true;
|
|
+
|
|
+ buf = getenv("WESTON_DRM_HEAD_FALLBACK_ALL");
|
|
+ if (buf && buf[0] == '1')
|
|
+ b->head_fallback_all = true;
|
|
+
|
|
+ buf = getenv("WESTON_DRM_PREFER_EXTERNAL");
|
|
+ if (buf && buf[0] == '1') {
|
|
+ head_mode = DRM_HEAD_MODE_EXTERNAL;
|
|
+ b->head_fallback = true;
|
|
+ }
|
|
+
|
|
+ buf = getenv("WESTON_DRM_PREFER_EXTERNAL_DUAL");
|
|
+ if (buf && buf[0] == '1')
|
|
+ head_mode = DRM_HEAD_MODE_EXTERNAL_DUAL;
|
|
+
|
|
+ buf = getenv("WESTON_DRM_HEAD_MODE");
|
|
+ if (buf) {
|
|
+ if (!strcmp(buf, "primary"))
|
|
+ head_mode = DRM_HEAD_MODE_PRIMARY;
|
|
+ else if (!strcmp(buf, "internal"))
|
|
+ head_mode = DRM_HEAD_MODE_INTERNAL;
|
|
+ else if (!strcmp(buf, "external"))
|
|
+ head_mode = DRM_HEAD_MODE_EXTERNAL;
|
|
+ else if (!strcmp(buf, "external-dual"))
|
|
+ head_mode = DRM_HEAD_MODE_EXTERNAL_DUAL;
|
|
+ }
|
|
+
|
|
+ b->head_matches = drm_head_matches[head_mode];
|
|
+
|
|
device = zalloc(sizeof *device);
|
|
if (device == NULL)
|
|
goto err_backend;
|
|
@@ -4102,6 +4368,7 @@ drm_backend_create(struct weston_compositor *compositor,
|
|
goto err_udev_dev;
|
|
}
|
|
|
|
+ b->base.late_init = drm_late_init;
|
|
b->base.shutdown = drm_shutdown;
|
|
b->base.destroy = drm_destroy;
|
|
b->base.repaint_begin = drm_repaint_begin;
|
|
@@ -4136,10 +4403,6 @@ drm_backend_create(struct weston_compositor *compositor,
|
|
}
|
|
|
|
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);
|
|
|
|
@@ -4175,6 +4438,10 @@ drm_backend_create(struct weston_compositor *compositor,
|
|
|
|
udev_device_unref(drm_device);
|
|
|
|
+ b->output_create_listener.notify = output_create_notify;
|
|
+ wl_signal_add(&b->compositor->output_created_signal,
|
|
+ &b->output_create_listener);
|
|
+
|
|
weston_compositor_add_debug_binding(compositor, KEY_O,
|
|
planes_binding, b);
|
|
weston_compositor_add_debug_binding(compositor, KEY_C,
|
|
@@ -4231,6 +4498,9 @@ drm_backend_create(struct weston_compositor *compositor,
|
|
goto err_udev_monitor;
|
|
}
|
|
|
|
+ b->hotplug_timer =
|
|
+ wl_event_loop_add_timer(loop, hotplug_timer_handler, b->drm);
|
|
+
|
|
return b;
|
|
|
|
err_udev_monitor:
|
|
@@ -4238,7 +4508,6 @@ err_udev_monitor:
|
|
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);
|
|
diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c
|
|
index c6d997625..30a95199f 100644
|
|
--- a/libweston/backend-drm/kms.c
|
|
+++ b/libweston/backend-drm/kms.c
|
|
@@ -860,6 +860,8 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
|
|
|
|
scanout_state =
|
|
drm_output_state_get_existing_plane(state, scanout_plane);
|
|
+ if (!scanout_state || !scanout_state->fb)
|
|
+ return 0;
|
|
|
|
/* The legacy SetCrtc API doesn't allow us to do scaling, and the
|
|
* legacy PageFlip API doesn't allow us to do clipping either. */
|
|
@@ -877,7 +879,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
|
|
assert(scanout_state->in_fence_fd == -1);
|
|
|
|
mode = to_drm_mode(output->base.current_mode);
|
|
- if (device->state_invalid ||
|
|
+ if (output->state_invalid ||
|
|
!scanout_plane->state_cur->fb ||
|
|
scanout_plane->state_cur->fb->strides[0] !=
|
|
scanout_state->fb->strides[0]) {
|
|
@@ -892,6 +894,8 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
|
|
goto err;
|
|
}
|
|
|
|
+ output->state_invalid = false;
|
|
+
|
|
if (!output->deprecated_gamma_is_set)
|
|
drm_output_reset_legacy_gamma(output);
|
|
}
|
|
@@ -1231,6 +1235,11 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
|
|
*flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
|
}
|
|
|
|
+ if (output->state_invalid) {
|
|
+ drm_debug(b, "\t\t\t[atomic] output state invalid, modeset OK\n");
|
|
+ *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
|
+ }
|
|
+
|
|
if (state->dpms == WESTON_DPMS_ON) {
|
|
ret = drm_mode_ensure_blob(device, current_mode);
|
|
if (ret != 0)
|
|
@@ -1562,13 +1571,14 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
|
|
}
|
|
|
|
wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
|
|
- link)
|
|
+ link) {
|
|
+ struct drm_output *output = output_state->output;
|
|
drm_output_assign_state(output_state, mode);
|
|
+ output->state_invalid = false;
|
|
+ }
|
|
|
|
device->state_invalid = false;
|
|
|
|
- assert(wl_list_empty(&pending_state->output_list));
|
|
-
|
|
out:
|
|
drmModeAtomicFree(req);
|
|
drm_pending_state_free(pending_state);
|
|
@@ -1673,8 +1683,6 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
|
|
|
|
device->state_invalid = false;
|
|
|
|
- assert(wl_list_empty(&pending_state->output_list));
|
|
-
|
|
drm_pending_state_free(pending_state);
|
|
|
|
return 0;
|
|
@@ -1726,8 +1734,6 @@ drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
|
|
|
|
device->state_invalid = false;
|
|
|
|
- assert(wl_list_empty(&pending_state->output_list));
|
|
-
|
|
drm_pending_state_free(pending_state);
|
|
|
|
return 0;
|
|
diff --git a/libweston/backend.h b/libweston/backend.h
|
|
index 05a40f30b..acb3a8f2e 100644
|
|
--- a/libweston/backend.h
|
|
+++ b/libweston/backend.h
|
|
@@ -42,6 +42,8 @@ struct weston_hdr_metadata_type1;
|
|
struct weston_backend {
|
|
struct wl_list link; /**< in weston_compositor::backend_list */
|
|
|
|
+ void (*late_init)(struct weston_backend *backend);
|
|
+
|
|
/** Bitfield of supported presentation clocks
|
|
*
|
|
* Bit positions correspond to system clock IDs.
|
|
diff --git a/libweston/compositor.c b/libweston/compositor.c
|
|
index 419d834a1..8bf6677b4 100644
|
|
--- a/libweston/compositor.c
|
|
+++ b/libweston/compositor.c
|
|
@@ -413,6 +413,25 @@ weston_paint_node_destroy(struct weston_paint_node *pnode)
|
|
free(pnode);
|
|
}
|
|
|
|
+static struct weston_layer *
|
|
+get_view_layer(struct weston_view *view);
|
|
+
|
|
+static bool
|
|
+weston_compositor_is_static_layer(struct weston_layer *layer)
|
|
+{
|
|
+ if (!layer)
|
|
+ return false;
|
|
+
|
|
+ switch (layer->position) {
|
|
+ case WESTON_LAYER_POSITION_BACKGROUND:
|
|
+ case WESTON_LAYER_POSITION_UI:
|
|
+ case WESTON_LAYER_POSITION_FADE:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
/** Send wl_output events for mode and scale changes
|
|
*
|
|
* \param head Send on all resources bound to this head.
|
|
@@ -1617,6 +1636,22 @@ weston_view_assign_output(struct weston_view *ev)
|
|
uint32_t new_output_area, area, mask;
|
|
pixman_box32_t *e;
|
|
|
|
+ /* The static views should bind to the specific output */
|
|
+ if (weston_compositor_is_static_layer(get_view_layer(ev))) {
|
|
+ struct weston_view *view = ev;
|
|
+
|
|
+ while (view && !(output = view->output))
|
|
+ view = view->geometry.parent;
|
|
+
|
|
+ if (output && !output->destroying)
|
|
+ ev->output_mask = 1u << output->id;
|
|
+ else
|
|
+ weston_view_set_output(ev, NULL);
|
|
+
|
|
+ weston_surface_assign_output(ev->surface);
|
|
+ return;
|
|
+ }
|
|
+
|
|
new_output = NULL;
|
|
new_output_area = 0;
|
|
mask = 0;
|
|
@@ -3715,6 +3750,11 @@ weston_output_flush_damage_for_primary_plane(struct weston_output *output,
|
|
WL_EXPORT void
|
|
weston_output_schedule_repaint_reset(struct weston_output *output)
|
|
{
|
|
+ if (output->idle_repaint_source) {
|
|
+ wl_event_source_remove(output->idle_repaint_source);
|
|
+ output->idle_repaint_source = NULL;
|
|
+ }
|
|
+
|
|
weston_output_put_back_feedback_list(output);
|
|
output->repaint_status = REPAINT_NOT_SCHEDULED;
|
|
TL_POINT(output->compositor, "core_repaint_exit_loop",
|
|
@@ -3782,10 +3822,28 @@ weston_output_repaint(struct weston_output *output, struct timespec *now)
|
|
|
|
output_accumulate_damage(output);
|
|
|
|
- r = output->repaint(output);
|
|
+ if (output->resizing) {
|
|
+ /* Resize maximized or fullscreen views(not always success) */
|
|
+ wl_signal_emit(&ec->output_resized_signal, output);
|
|
+ }
|
|
+
|
|
+ if (output->resizing) {
|
|
+ int64_t refresh_nsec =
|
|
+ millihz_to_nsec(output->current_mode->refresh);
|
|
+ timespec_add_nsec(&output->next_repaint,
|
|
+ &output->next_repaint, refresh_nsec);
|
|
+ r = 1;
|
|
+ } else {
|
|
+ r = output->repaint(output);
|
|
+ }
|
|
|
|
output->repaint_needed = false;
|
|
- if (r == 0) {
|
|
+
|
|
+ /* HACK: Retry repaint again */
|
|
+ if (r > 0) {
|
|
+ weston_output_schedule_repaint(output);
|
|
+ r = 0;
|
|
+ } else if (r == 0) {
|
|
output->repaint_status = REPAINT_AWAITING_COMPLETION;
|
|
output->repainted = true;
|
|
}
|
|
@@ -3947,7 +4005,7 @@ output_repaint_timer_handler(void *data)
|
|
struct weston_backend *backend;
|
|
struct weston_output *output;
|
|
struct timespec now;
|
|
- int ret = 0;
|
|
+ int ret = 0, repainted = 0;
|
|
|
|
if (!access(getenv("WESTON_FREEZE_DISPLAY") ? : "", F_OK)) {
|
|
usleep(DEFAULT_REPAINT_WINDOW * 1000);
|
|
@@ -3990,8 +4048,10 @@ output_repaint_timer_handler(void *data)
|
|
ret = weston_output_repaint(output, &now);
|
|
if (ret)
|
|
break;
|
|
+
|
|
+ repainted |= output->repainted;
|
|
}
|
|
- if (ret == 0) {
|
|
+ if (ret == 0 && repainted) {
|
|
if (backend->repaint_flush)
|
|
backend->repaint_flush(backend);
|
|
} else {
|
|
@@ -7308,6 +7368,8 @@ weston_compositor_reflow_outputs(struct weston_compositor *compositor)
|
|
|
|
weston_output_set_position(output, output->mirror_of->pos);
|
|
}
|
|
+
|
|
+ compositor->view_list_needs_rebuild = true;
|
|
}
|
|
|
|
/** Transform a region from global to output coordinates
|
|
@@ -7504,6 +7566,10 @@ weston_compositor_add_output(struct weston_compositor *compositor,
|
|
weston_view_geometry_dirty_internal(view);
|
|
|
|
compositor->view_list_needs_rebuild = true;
|
|
+
|
|
+ /* Ensure maximized and fullscreen surfaces resized */
|
|
+ if (compositor->block_output_resizing)
|
|
+ output->resizing = true;
|
|
}
|
|
|
|
/** Create a weston_coord_global from a point and a weston_output
|
|
@@ -9835,6 +9901,10 @@ weston_compositor_backends_loaded(struct weston_compositor *compositor)
|
|
return -1;
|
|
}
|
|
|
|
+ wl_list_for_each(backend, &compositor->backend_list, link)
|
|
+ if (backend->late_init)
|
|
+ backend->late_init(backend);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -9852,10 +9922,10 @@ weston_compositor_backends_loaded(struct weston_compositor *compositor)
|
|
*
|
|
* \ingroup compositor
|
|
*/
|
|
-WL_EXPORT void
|
|
+ WL_EXPORT void
|
|
weston_compositor_read_presentation_clock(
|
|
- struct weston_compositor *compositor,
|
|
- struct timespec *ts)
|
|
+ struct weston_compositor *compositor,
|
|
+ struct timespec *ts)
|
|
{
|
|
int ret;
|
|
|
|
--
|
|
2.20.1
|
|
|