From 02fd08a2e640ceb9dfa7d0fd2efde6a0ff3047ca Mon Sep 17 00:00:00 2001
|
From: Jeffy Chen <jeffy.chen@rock-chips.com>
|
Date: Fri, 3 Jul 2020 12:37:37 +0800
|
Subject: [PATCH 16/79] backend-drm: Support controlling output dynamically
|
|
Use config file to set output's rotate/down-scale/size/pos/mode/off/
|
freeze/display-rectangle and prefer/primary output.
|
|
Default config file is "/tmp/.weston_drm.conf", can override with
|
"WESTON_DRM_CONFIG" environment.
|
|
Supported configs format is "output:<output name>:<config>", for
|
example:
|
echo "output:DSI-1:off" >> /tmp/.weston_drm.conf
|
echo "output:eDP-1:freeze" >> /tmp/.weston_drm.conf
|
echo "output:all:rotate90" >> /tmp/.weston_drm.conf
|
echo "output:all:rect=<100,20,1636,2068>" >> /tmp/.weston_drm.conf
|
echo "output:HDMI-A-1:mode=800x600" >> /tmp/.weston_drm.conf
|
echo "output:HDMI-A-1:pos=100,200" >> /tmp/.weston_drm.conf
|
echo "output:HDMI-A-1:size=1920x1080" >> /tmp/.weston_drm.conf
|
echo "output:HDMI-A-1:prefer" >> /tmp/.weston_drm.conf
|
echo "output:HDMI-A-1:primary" >> /tmp/.weston_drm.conf
|
echo "output:HDMI-A-1:down-scale=0.5" >> /tmp/.weston_drm.conf
|
|
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
|
---
|
compositor/main.c | 14 ++
|
desktop-shell/shell.c | 58 +++++-
|
include/libweston/libweston.h | 7 +
|
libweston/backend-drm/drm-internal.h | 16 ++
|
libweston/backend-drm/drm.c | 264 ++++++++++++++++++++++++++-
|
libweston/backend-drm/modes.c | 20 +-
|
libweston/compositor.c | 50 +++--
|
libweston/pixman-renderer.c | 3 +
|
libweston/renderer-gl/gl-renderer.c | 4 +
|
9 files changed, 397 insertions(+), 39 deletions(-)
|
|
diff --git a/compositor/main.c b/compositor/main.c
|
index 47bf540..a4f679a 100644
|
--- a/compositor/main.c
|
+++ b/compositor/main.c
|
@@ -1832,6 +1832,20 @@ drm_backend_output_configure(struct weston_output *output,
|
}
|
free(s);
|
|
+ weston_config_section_get_string(section, "pos", &s, NULL);
|
+ if (s) {
|
+ if (sscanf(s, "%d,%d", &output->x, &output->y) == 2)
|
+ output->fixed_position = true;
|
+ free(s);
|
+ }
|
+
|
+ weston_config_section_get_string(section, "size", &s, NULL);
|
+ if (s) {
|
+ if (sscanf(s, "%dx%d", &output->width, &output->height) == 2)
|
+ output->fixed_size = true;
|
+ free(s);
|
+ }
|
+
|
if (api->set_mode(output, mode, modeline) < 0) {
|
weston_log("Cannot configure an output using weston_drm_output_api.\n");
|
free(modeline);
|
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
|
index 18bec12..8b4ed45 100644
|
--- a/desktop-shell/shell.c
|
+++ b/desktop-shell/shell.c
|
@@ -4254,7 +4254,7 @@ weston_view_set_initial_position(struct weston_view *view,
|
int ix = 0, iy = 0;
|
int32_t range_x, range_y;
|
int32_t x, y;
|
- struct weston_output *output, *target_output = NULL;
|
+ struct weston_output *output, *target_output = NULL, *prefer_output = NULL;
|
struct weston_seat *seat;
|
pixman_rectangle32_t area;
|
|
@@ -4279,16 +4279,20 @@ weston_view_set_initial_position(struct weston_view *view,
|
}
|
}
|
|
- wl_list_for_each(output, &compositor->output_list, link) {
|
+ wl_list_for_each_reverse(output, &compositor->output_list, link) {
|
if (output->unavailable)
|
continue;
|
|
- if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) {
|
+ if (output == compositor->prefer_output)
|
+ prefer_output = output;
|
+
|
+ if (pixman_region32_contains_point(&output->region, ix, iy, NULL))
|
target_output = output;
|
- break;
|
- }
|
}
|
|
+ if (prefer_output)
|
+ target_output = prefer_output;
|
+
|
if (!target_output) {
|
weston_view_set_position(view, 10 + random() % 400,
|
10 + random() % 400);
|
@@ -4890,6 +4894,41 @@ shell_resize_surface_to_output(struct desktop_shell *shell,
|
output->height);
|
}
|
|
+static void
|
+handle_output_resize_layer(struct desktop_shell *shell,
|
+ struct weston_layer *layer, void *data)
|
+{
|
+ struct weston_output *output = data;
|
+ struct weston_view *view;
|
+
|
+ wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
|
+ struct weston_desktop_surface *desktop_surface;
|
+ struct shell_surface *shsurf;
|
+ bool dirty = false;
|
+
|
+ if (view->output != output)
|
+ continue;
|
+
|
+ shsurf = get_shell_surface(view->surface);
|
+ if (!shsurf)
|
+ continue;
|
+
|
+ desktop_surface = shsurf->desktop_surface;
|
+ if (weston_desktop_surface_get_fullscreen(desktop_surface)) {
|
+ set_fullscreen(shsurf, true, output);
|
+ dirty = true;
|
+ }
|
+ if (weston_desktop_surface_get_maximized(desktop_surface)) {
|
+ set_maximized(shsurf, true);
|
+ dirty = true;
|
+ }
|
+
|
+ if (dirty) {
|
+ weston_view_geometry_dirty(view);
|
+ weston_surface_damage(view->surface);
|
+ }
|
+ }
|
+}
|
|
static void
|
handle_output_resized(struct wl_listener *listener, void *data)
|
@@ -4899,8 +4938,13 @@ 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);
|
|
+ if (shell->lock_surface)
|
+ shell->lock_surface->committed(shell->lock_surface, 0, 0);
|
+
|
shell_resize_surface_to_output(shell, sh_output->background_surface, output);
|
shell_resize_surface_to_output(shell, sh_output->panel_surface, output);
|
+
|
+ shell_for_each_layer(shell, handle_output_resize_layer, data);
|
}
|
|
static void
|
@@ -4949,7 +4993,9 @@ handle_output_move_layer(struct desktop_shell *shell,
|
|
x = view->geometry.x + output->move_x;
|
y = view->geometry.y + output->move_y;
|
- weston_view_set_position(view, x, y);
|
+
|
+ if (pixman_region32_contains_point(&output->region, x, y, NULL))
|
+ weston_view_set_position(view, x, y);
|
}
|
}
|
|
diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h
|
index 8868622..24e44a2 100644
|
--- a/include/libweston/libweston.h
|
+++ b/include/libweston/libweston.h
|
@@ -413,6 +413,12 @@ struct weston_output {
|
struct weston_head *head);
|
|
bool unavailable;
|
+ bool freezing;
|
+
|
+ bool fixed_position;
|
+ bool fixed_size;
|
+
|
+ double down_scale;
|
};
|
#define weston_output_valid(o) \
|
((o) && !(o)->destroying && !(o)->unavailable)
|
@@ -1198,6 +1204,7 @@ struct weston_compositor {
|
struct content_protection *content_protection;
|
|
enum weston_output_flow output_flow;
|
+ struct weston_output *prefer_output;
|
};
|
|
struct weston_buffer {
|
diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
|
index 1625be2..9d24017 100644
|
--- a/libweston/backend-drm/drm-internal.h
|
+++ b/libweston/backend-drm/drm-internal.h
|
@@ -115,6 +115,9 @@
|
|
#define DRM_RESIZE_FREEZE_MS 600
|
|
+#define WESTON_DRM_CONFIG_FILE "/tmp/.weston_drm.conf"
|
+#define DRM_CONFIG_UPDATE_MS 100
|
+
|
/**
|
* Represents the values of an enum-type KMS property
|
*/
|
@@ -348,6 +351,9 @@ struct drm_backend {
|
int virtual_height;
|
|
bool mirror_mode;
|
+
|
+ struct wl_event_source *config_timer;
|
+ struct stat config_stat;
|
};
|
|
struct drm_mode {
|
@@ -626,6 +632,9 @@ struct drm_output {
|
bool is_mirror;
|
|
pixman_box32_t plane_bounds;
|
+
|
+ uint32_t original_transform;
|
+ int64_t last_resize_ms;
|
};
|
|
static inline struct drm_head *
|
@@ -708,6 +717,13 @@ drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list);
|
void
|
drm_output_print_modes(struct drm_output *output);
|
|
+struct drm_mode *
|
+drm_output_choose_initial_mode(struct drm_backend *backend,
|
+ struct drm_output *output,
|
+ enum weston_drm_backend_output_mode mode,
|
+ const char *modeline,
|
+ const drmModeModeInfo *current_mode);
|
+
|
int
|
drm_output_set_mode(struct weston_output *base,
|
enum weston_drm_backend_output_mode mode,
|
diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
|
index 696df68..1d6f7db 100644
|
--- a/libweston/backend-drm/drm.c
|
+++ b/libweston/backend-drm/drm.c
|
@@ -40,6 +40,7 @@
|
#include <linux/vt.h>
|
#include <assert.h>
|
#include <sys/mman.h>
|
+#include <sys/stat.h>
|
#include <time.h>
|
|
#include <xf86drm.h>
|
@@ -74,6 +75,8 @@
|
|
static const char default_seat[] = "seat0";
|
|
+static int config_timer_handler(void *data);
|
+
|
static inline bool
|
drm_head_is_external(struct drm_head *head)
|
{
|
@@ -205,7 +208,7 @@ close_src:
|
static void
|
drm_backend_update_outputs(struct drm_backend *b)
|
{
|
- struct weston_output *primary;
|
+ struct weston_output *base, *primary;
|
|
if (!b->primary_head)
|
return;
|
@@ -493,6 +496,12 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags,
|
return;
|
}
|
|
+ if (!sec && !usec) {
|
+ weston_output_finish_frame(&output->base, NULL,
|
+ WP_PRESENTATION_FEEDBACK_INVALID);
|
+ return;
|
+ }
|
+
|
ts.tv_sec = sec;
|
ts.tv_nsec = usec * 1000;
|
|
@@ -671,8 +680,8 @@ out:
|
return;
|
}
|
|
- sw = fb->width;
|
- sh = fb->height;
|
+ sw = fb->width * output->base.down_scale;
|
+ sh = fb->height * output->base.down_scale;
|
|
dx = output->plane_bounds.x1;
|
dy = output->plane_bounds.y1;
|
@@ -823,7 +832,8 @@ drm_output_repaint(struct weston_output *output_base,
|
|
weston_compositor_read_presentation_clock(b->compositor, &now);
|
now_ms = timespec_to_msec(&now);
|
- if (now_ms < b->last_resize_ms + b->resize_freeze_ms) {
|
+ if (now_ms < b->last_resize_ms + b->resize_freeze_ms ||
|
+ now_ms < output->last_resize_ms + b->resize_freeze_ms) {
|
/* Resize fullscreen/maxmium views(not always success) */
|
if (now_ms < b->last_resize_ms + DRM_RESIZE_FREEZE_MS)
|
wl_signal_emit(&b->compositor->output_resized_signal,
|
@@ -832,7 +842,7 @@ drm_output_repaint(struct weston_output *output_base,
|
weston_output_damage(output_base);
|
weston_output_finish_frame(output_base, NULL,
|
WP_PRESENTATION_FEEDBACK_INVALID);
|
- return 0;
|
+ goto not_repainted;
|
}
|
|
/* If planes have been disabled in the core, we might not have
|
@@ -860,7 +870,8 @@ drm_output_repaint(struct weston_output *output_base,
|
|
err:
|
drm_output_state_free(state);
|
- return 0;
|
+not_repainted:
|
+ return 1;
|
}
|
|
/* Determine the type of vblank synchronization to use for the output.
|
@@ -2213,6 +2224,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->original_transform = output->base.transform;
|
+
|
output->state_invalid = true;
|
|
weston_log("Output %s (crtc %d) video modes:\n",
|
@@ -3061,6 +3074,7 @@ drm_destroy(struct weston_compositor *ec)
|
|
udev_input_destroy(&b->input);
|
|
+ wl_event_source_remove(b->config_timer);
|
wl_event_source_remove(b->hotplug_timer);
|
wl_event_source_remove(b->udev_drm_source);
|
wl_event_source_remove(b->drm_source);
|
@@ -3483,6 +3497,10 @@ output_create_notify(struct wl_listener *listener, void *data)
|
output_create_listener);
|
|
drm_backend_update_outputs(b);
|
+
|
+ /* Force reload config */
|
+ memset(&b->config_stat, 0, sizeof(b->config_stat));
|
+ config_timer_handler(b);
|
}
|
|
static const struct weston_drm_output_api api = {
|
@@ -3491,6 +3509,236 @@ static const struct weston_drm_output_api api = {
|
drm_output_set_seat,
|
};
|
|
+static void
|
+drm_output_rotate(struct drm_output *output, int rotate)
|
+{
|
+ struct drm_backend *b = to_drm_backend(output->base.compositor);
|
+ uint32_t transform = output->original_transform;
|
+ struct timespec now;
|
+
|
+ /* Hacky way to rotate transform */
|
+ transform = (transform / 4) * 4 + (transform + rotate) % 4;
|
+
|
+ if (output->base.transform == transform)
|
+ return;
|
+
|
+ /* Freeze output when rotating */
|
+ weston_compositor_read_presentation_clock(b->compositor, &now);
|
+ output->last_resize_ms = timespec_to_msec(&now);
|
+
|
+ weston_output_set_transform(&output->base, transform);
|
+}
|
+
|
+static void
|
+drm_output_modeset(struct drm_output *output, const char *modeline)
|
+{
|
+ struct drm_backend *b = to_drm_backend(output->base.compositor);
|
+ struct drm_head *head =
|
+ to_drm_head(weston_output_get_first_head(&output->base));
|
+ struct drm_mode *mode;
|
+ struct timespec now;
|
+
|
+ /* Unable to switch mode, let's retry later */
|
+ if (output->page_flip_pending || output->atomic_complete_pending) {
|
+ memset(&b->config_stat, 0, sizeof(b->config_stat));
|
+ return;
|
+ }
|
+
|
+ mode = drm_output_choose_initial_mode(b, output,
|
+ WESTON_DRM_BACKEND_OUTPUT_PREFERRED,
|
+ modeline,
|
+ &head->inherited_mode);
|
+
|
+ weston_output_mode_set_native(&output->base, &mode->base,
|
+ output->base.current_scale);
|
+ weston_output_damage(&output->base);
|
+
|
+ mode = to_drm_mode(output->base.current_mode);
|
+
|
+ weston_log("Output %s changed to %dx%d@%d for mode(%s)\n",
|
+ output->base.name,
|
+ mode->mode_info.hdisplay, mode->mode_info.vdisplay,
|
+ mode->mode_info.vrefresh,
|
+ modeline);
|
+
|
+ weston_compositor_read_presentation_clock(b->compositor, &now);
|
+ b->last_update_ms = timespec_to_msec(&now);
|
+}
|
+
|
+static void
|
+drm_output_set_size(struct drm_output *output, const int w, const int h)
|
+{
|
+ struct drm_backend *b = to_drm_backend(output->base.compositor);
|
+ struct weston_mode *mode;
|
+ struct timespec now;
|
+
|
+ if (output->base.fixed_size &&
|
+ output->base.current_mode->width == w &&
|
+ output->base.current_mode->height == h)
|
+ return;
|
+
|
+ wl_list_for_each(mode, &output->base.mode_list, link) {
|
+ mode->width = w;
|
+ mode->height = h;
|
+ }
|
+
|
+ output->base.fixed_size = true;
|
+
|
+ /* Freeze output when resizing */
|
+ weston_compositor_read_presentation_clock(b->compositor, &now);
|
+ output->last_resize_ms = timespec_to_msec(&now);
|
+
|
+ weston_output_set_transform(&output->base, output->base.transform);
|
+
|
+ if (b->use_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");
|
+ } 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");
|
+ }
|
+
|
+ drm_output_print_modes(output);
|
+}
|
+
|
+static void
|
+config_handle_output(struct drm_backend *b, const char *name,
|
+ const char *config)
|
+{
|
+ struct drm_output *output;
|
+ bool is_all = !strcmp(name, "all");
|
+
|
+ wl_list_for_each(output, &b->compositor->output_list, base.link) {
|
+ if (!is_all && strcmp(name, output->base.name))
|
+ continue;
|
+
|
+ if (!strcmp(config, "primary")) {
|
+ setenv("WESTON_DRM_PRIMARY", name, 1);
|
+ hotplug_timer_handler(b);
|
+ } else if (!strcmp(config, "prefer")) {
|
+ b->compositor->prefer_output = &output->base;
|
+ } else if (!strncmp(config, "rotate", strlen("rotate"))) {
|
+ int rotate = atoi(config + strlen("rotate")) / 90;
|
+ drm_output_rotate(output, rotate);
|
+ } else if (!strncmp(config, "mode=", strlen("mode="))) {
|
+ drm_output_modeset(output, config + strlen("mode="));
|
+ } else if (!strcmp(config, "freeze")) {
|
+ output->base.freezing = true;
|
+ } else if (!strcmp(config, "off")) {
|
+ output->base.freezing = true;
|
+ if (!output->virtual)
|
+ drm_set_dpms(&output->base, WESTON_DPMS_OFF);
|
+ } else if (!strcmp(config, "unfreeze") ||
|
+ !strcmp(config, "on")) {
|
+ if (!output->base.freezing)
|
+ continue;
|
+
|
+ output->base.freezing = false;
|
+
|
+ if (!output->virtual)
|
+ drm_set_dpms(&output->base, WESTON_DPMS_ON);
|
+
|
+ drm_output_update_complete(output, 0, 0, 0);
|
+ output->page_flip_pending = false;
|
+ output->atomic_complete_pending = false;
|
+
|
+ weston_output_damage(&output->base);
|
+ } else if (!strncmp(config, "down-scale=",
|
+ strlen("down-scale="))) {
|
+ double down_scale =
|
+ atof(config + strlen("down-scale="));
|
+ if (down_scale == output->base.down_scale ||
|
+ down_scale < 0.125 || down_scale > 1)
|
+ continue;
|
+
|
+ output->base.down_scale = down_scale;
|
+ weston_output_damage(&output->base);
|
+ } else if (!strncmp(config, "size=", strlen("size="))) {
|
+ int w, h;
|
+
|
+ if (sscanf(config, "size=%dx%d", &w, &h) != 2)
|
+ continue;
|
+
|
+ drm_output_set_size(output, w, h);
|
+ } else if (!strncmp(config, "pos=", strlen("pos="))) {
|
+ int x, y;
|
+
|
+ if (sscanf(config, "pos=%d,%d", &x, &y) != 2)
|
+ continue;
|
+
|
+ weston_output_move(&output->base, x, y);
|
+ output->base.fixed_position = true;
|
+
|
+ weston_compositor_reflow_outputs(b->compositor);
|
+ } else if (!strncmp(config, "rect=", strlen("rect="))) {
|
+ int x1, y1, x2, y2, ret;
|
+
|
+ ret = sscanf(config, "rect=<%d,%d,%d,%d>",
|
+ &x1, &y1, &x2, &y2);
|
+ if (ret != 4)
|
+ continue;
|
+
|
+ output->plane_bounds.x1 = x1;
|
+ output->plane_bounds.y1 = y1;
|
+ output->plane_bounds.x2 = x2;
|
+ output->plane_bounds.y2 = y2;
|
+ weston_output_schedule_repaint(&output->base);
|
+ }
|
+ }
|
+}
|
+
|
+static int
|
+config_timer_handler(void *data)
|
+{
|
+#define MAX_CONF_LEN 32
|
+#define _STR(x) #x
|
+#define STR(x) _STR(x)
|
+
|
+ struct drm_backend *b = data;
|
+ struct stat st;
|
+ char type[MAX_CONF_LEN], key[MAX_CONF_LEN], value[MAX_CONF_LEN];
|
+ const char *config_file;
|
+ FILE *conf_fp;
|
+
|
+ wl_event_source_timer_update(b->config_timer, DRM_CONFIG_UPDATE_MS);
|
+
|
+ config_file = getenv("WESTON_DRM_CONFIG");
|
+ if (!config_file)
|
+ config_file = WESTON_DRM_CONFIG_FILE;
|
+
|
+ if (stat(config_file, &st) < 0)
|
+ return 0;
|
+
|
+ if (st.st_mtime && !memcmp(&st, &b->config_stat, sizeof(st)))
|
+ return 0;
|
+
|
+ conf_fp = fopen(config_file, "r");
|
+ if (!conf_fp)
|
+ return 0;
|
+
|
+ /**
|
+ * Parse configs, formated with <type>:<key>:<value>
|
+ * For example: "output:all:rotate90"
|
+ */
|
+ while (3 == fscanf(conf_fp,
|
+ "%" STR(MAX_CONF_LEN) "[^:]:"
|
+ "%" STR(MAX_CONF_LEN) "[^:]:"
|
+ "%" STR(MAX_CONF_LEN) "s ", type, key, value)) {
|
+ if (!strcmp(type, "output"))
|
+ config_handle_output(b, key, value);
|
+ }
|
+
|
+ fclose(conf_fp);
|
+
|
+ stat(config_file, &st);
|
+ b->config_stat = st;
|
+ return 0;
|
+}
|
+
|
enum drm_head_mode {
|
DRM_HEAD_MODE_DEFAULT,
|
DRM_HEAD_MODE_PRIMARY,
|
@@ -3830,6 +4078,10 @@ drm_backend_create(struct weston_compositor *compositor,
|
b->hotplug_timer =
|
wl_event_loop_add_timer(loop, hotplug_timer_handler, b);
|
|
+ b->config_timer =
|
+ wl_event_loop_add_timer(loop, config_timer_handler, b);
|
+ config_timer_handler(b);
|
+
|
return b;
|
|
err_udev_monitor:
|
diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c
|
index e7bbfa5..ff7421d 100644
|
--- a/libweston/backend-drm/modes.c
|
+++ b/libweston/backend-drm/modes.c
|
@@ -385,15 +385,19 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
|
if (mode == NULL)
|
return NULL;
|
|
- mode->base.flags = 0;
|
- mode->base.width = info->hdisplay;
|
- mode->base.height = info->vdisplay;
|
-
|
- if (b->virtual_width && b->virtual_height) {
|
+ if (output->base.fixed_size) {
|
+ mode->base.width = output->base.width;
|
+ mode->base.height = output->base.height;
|
+ } else if (b->virtual_width && b->virtual_height) {
|
mode->base.width = b->virtual_width;
|
mode->base.height = b->virtual_height;
|
+ } else {
|
+ mode->base.width = info->hdisplay;
|
+ mode->base.height = info->vdisplay;
|
}
|
|
+ mode->base.flags = 0;
|
+
|
mode->base.refresh = drm_refresh_rate_mHz(info);
|
mode->mode_info = *info;
|
mode->blob_id = 0;
|
@@ -566,7 +570,7 @@ update_head_from_connector(struct drm_head *head)
|
* @param current_mode Mode currently being displayed on this output
|
* @returns A mode from the output's mode list, or NULL if none available
|
*/
|
-static struct drm_mode *
|
+struct drm_mode *
|
drm_output_choose_initial_mode(struct drm_backend *backend,
|
struct drm_output *output,
|
enum weston_drm_backend_output_mode mode,
|
@@ -619,8 +623,8 @@ drm_output_choose_initial_mode(struct drm_backend *backend,
|
}
|
|
wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
|
- if (width == drm_mode->base.width &&
|
- height == drm_mode->base.height &&
|
+ if (width == drm_mode->mode_info.hdisplay &&
|
+ height == drm_mode->mode_info.vdisplay &&
|
(refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) {
|
if (!backend->aspect_ratio_supported ||
|
aspect_ratio == drm_mode->base.aspect_ratio)
|
diff --git a/libweston/compositor.c b/libweston/compositor.c
|
index 7680445..0aa9d1a 100644
|
--- a/libweston/compositor.c
|
+++ b/libweston/compositor.c
|
@@ -3009,6 +3009,11 @@ weston_output_repaint(struct weston_output *output, void *repaint_data)
|
static 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;
|
+ }
|
+
|
output->repaint_status = REPAINT_NOT_SCHEDULED;
|
TL_POINT(output->compositor, "core_repaint_exit_loop",
|
TLP_OUTPUT(output), TLP_END);
|
@@ -3022,6 +3027,11 @@ weston_output_maybe_repaint(struct weston_output *output, struct timespec *now,
|
int ret = 0;
|
int64_t msec_to_repaint;
|
|
+ /* If we're sleeping, drop the repaint machinery entirely; we will
|
+ * explicitly repaint it when we come back. */
|
+ if (output->freezing)
|
+ goto err;
|
+
|
/* We're not ready yet; come back to make a decision later. */
|
if (output->repaint_status != REPAINT_SCHEDULED)
|
return ret;
|
@@ -3048,11 +3058,11 @@ weston_output_maybe_repaint(struct weston_output *output, struct timespec *now,
|
* output. */
|
ret = weston_output_repaint(output, repaint_data);
|
weston_compositor_read_presentation_clock(compositor, now);
|
- if (ret != 0)
|
+ if (ret < 0)
|
goto err;
|
|
- output->repainted = true;
|
- return ret;
|
+ output->repainted = !ret;
|
+ return 0;
|
|
err:
|
weston_output_schedule_repaint_reset(output);
|
@@ -3105,7 +3115,7 @@ output_repaint_timer_handler(void *data)
|
struct weston_output *output;
|
struct timespec now;
|
void *repaint_data = NULL;
|
- int ret = 0;
|
+ int ret = 0, repainted = 0;
|
|
if (!access(getenv("WESTON_FREEZE_DISPLAY") ? : "", F_OK)) {
|
usleep(DEFAULT_REPAINT_WINDOW * 1000);
|
@@ -3122,9 +3132,11 @@ output_repaint_timer_handler(void *data)
|
ret = weston_output_maybe_repaint(output, &now, repaint_data);
|
if (ret)
|
break;
|
+
|
+ repainted |= output->repainted;
|
}
|
|
- if (ret == 0) {
|
+ if (ret == 0 && repainted) {
|
if (compositor->backend->repaint_flush)
|
ret = compositor->backend->repaint_flush(compositor,
|
repaint_data);
|
@@ -6099,7 +6111,7 @@ weston_compositor_reflow_outputs(struct weston_compositor *compositor)
|
wl_list_for_each(head, &output->head_list, output_link)
|
weston_head_update_global(head);
|
|
- if (!weston_output_valid(output))
|
+ if (!weston_output_valid(output) || output->fixed_position)
|
continue;
|
|
x = next_x;
|
@@ -6546,6 +6558,9 @@ weston_output_set_transform(struct weston_output *output,
|
|
weston_compositor_reflow_outputs(output->compositor);
|
|
+ wl_signal_emit(&output->compositor->output_resized_signal,
|
+ output);
|
+
|
/* Notify clients of the change for output transform. */
|
wl_list_for_each(head, &output->head_list, output_link) {
|
wl_resource_for_each(resource, &head->resource_list) {
|
@@ -6678,6 +6693,8 @@ weston_output_init(struct weston_output *output,
|
/* Can't use -1 on uint32_t and 0 is valid enum value */
|
output->transform = UINT32_MAX;
|
|
+ output->down_scale = 1.0f;
|
+
|
pixman_region32_init(&output->region);
|
wl_list_init(&output->mode_list);
|
}
|
@@ -6769,11 +6786,8 @@ weston_output_create_heads_string(struct weston_output *output)
|
WL_EXPORT int
|
weston_output_enable(struct weston_output *output)
|
{
|
- struct weston_compositor *c = output->compositor;
|
- struct weston_output *iterator;
|
struct weston_head *head;
|
char *head_names;
|
- int x = 0, y = 0;
|
|
if (output->enabled) {
|
weston_log("Error: attempt to enable an enabled output '%s'\n",
|
@@ -6798,20 +6812,17 @@ weston_output_enable(struct weston_output *output)
|
assert(head->model);
|
}
|
|
- iterator = container_of(c->output_list.prev,
|
- struct weston_output, link);
|
-
|
- if (!wl_list_empty(&c->output_list))
|
- x = iterator->x + iterator->width;
|
-
|
/* Make sure the scale is set up */
|
assert(output->scale);
|
|
/* Make sure we have a transform set */
|
assert(output->transform != UINT32_MAX);
|
|
- output->x = x;
|
- output->y = y;
|
+ if (!output->fixed_position) {
|
+ output->x = 0;
|
+ output->y = 0;
|
+ }
|
+
|
output->original_scale = output->scale;
|
|
wl_signal_init(&output->frame_signal);
|
@@ -6820,8 +6831,7 @@ weston_output_enable(struct weston_output *output)
|
weston_output_transform_scale_init(output, output->transform, output->scale);
|
weston_output_init_zoom(output);
|
|
- weston_output_init_geometry(output, x, y);
|
- weston_output_damage(output);
|
+ weston_output_init_geometry(output, output->x, output->y);
|
|
wl_list_init(&output->animation_list);
|
wl_list_init(&output->feedback_list);
|
@@ -6848,6 +6858,8 @@ weston_output_enable(struct weston_output *output)
|
output->name, head_names);
|
free(head_names);
|
|
+ weston_compositor_reflow_outputs(output->compositor);
|
+
|
return 0;
|
}
|
|
diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c
|
index 754adce..d7182e7 100644
|
--- a/libweston/pixman-renderer.c
|
+++ b/libweston/pixman-renderer.c
|
@@ -158,6 +158,9 @@ pixman_renderer_compute_transform(pixman_transform_t *transform_out,
|
specified buffer transform/scale */
|
matrix = output->inverse_matrix;
|
|
+ weston_matrix_scale(&matrix,
|
+ 1 / output->down_scale, 1 / output->down_scale, 1);
|
+
|
if (ev->transform.enabled) {
|
weston_matrix_multiply(&matrix, &ev->transform.inverse);
|
} else {
|
diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c
|
index 6e04baa..f853149 100644
|
--- a/libweston/renderer-gl/gl-renderer.c
|
+++ b/libweston/renderer-gl/gl-renderer.c
|
@@ -1720,6 +1720,10 @@ gl_renderer_repaint_output(struct weston_output *output,
|
|
/* Calculate the global GL matrix */
|
go->output_matrix = output->matrix;
|
+
|
+ weston_matrix_scale(&go->output_matrix,
|
+ output->down_scale, output->down_scale, 1);
|
+
|
weston_matrix_translate(&go->output_matrix,
|
-(output->current_mode->width / 2.0),
|
-(output->current_mode->height / 2.0), 0);
|
--
|
2.20.1
|