1*4882a593SmuzhiyunFrom 14a416a3c5959e53d0de2e8cc7b8221a3544be5a Mon Sep 17 00:00:00 2001 2*4882a593SmuzhiyunFrom: Jeffy Chen <jeffy.chen@rock-chips.com> 3*4882a593SmuzhiyunDate: Tue, 23 Jun 2020 10:05:48 +0800 4*4882a593SmuzhiyunSubject: [PATCH 15/93] backend-drm: Support selecting monitors 5*4882a593Smuzhiyun 6*4882a593SmuzhiyunUsing these environments: 7*4882a593Smuzhiyun 8*4882a593SmuzhiyunWESTON_DRM_PRIMARY: 9*4882a593Smuzhiyun Specify primary connector. 10*4882a593SmuzhiyunWESTON_DRM_SINGLE_HEAD: 11*4882a593Smuzhiyun Force using single connector. 12*4882a593SmuzhiyunWESTON_DRM_HEAD_FALLBACK: 13*4882a593Smuzhiyun Fallback to any available connector if none matched. 14*4882a593SmuzhiyunWESTON_DRM_HEAD_FALLBACK_ALL: 15*4882a593Smuzhiyun Fallback to all available connector if none matched. 16*4882a593SmuzhiyunWESTON_DRM_PREFER_EXTERNAL_DUAL: 17*4882a593Smuzhiyun Prefer external connectors, and also enable internal ones. 18*4882a593SmuzhiyunWESTON_DRM_PREFER_EXTERNAL: 19*4882a593Smuzhiyun Prefer external connectors, and disable internal ones if any matched. 20*4882a593Smuzhiyun 21*4882a593SmuzhiyunWESTON_DRM_HEAD_MODE: 22*4882a593Smuzhiyun default(match primary->internal->external) 23*4882a593Smuzhiyun primary(match primary only) 24*4882a593Smuzhiyun internal(match primary->internal) 25*4882a593Smuzhiyun external(match primary->external) 26*4882a593Smuzhiyun external-dual(match primary->external->internal) 27*4882a593Smuzhiyun 28*4882a593SmuzhiyunSigned-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> 29*4882a593Smuzhiyun--- 30*4882a593Smuzhiyun compositor/main.c | 22 +- 31*4882a593Smuzhiyun desktop-shell/shell.c | 26 +- 32*4882a593Smuzhiyun include/libweston/libweston.h | 2 + 33*4882a593Smuzhiyun libweston/backend-drm/drm-internal.h | 24 ++ 34*4882a593Smuzhiyun libweston/backend-drm/drm.c | 378 ++++++++++++++++++++++++--- 35*4882a593Smuzhiyun libweston/backend-drm/kms.c | 42 ++- 36*4882a593Smuzhiyun libweston/compositor.c | 42 ++- 37*4882a593Smuzhiyun 7 files changed, 477 insertions(+), 59 deletions(-) 38*4882a593Smuzhiyun 39*4882a593Smuzhiyundiff --git a/compositor/main.c b/compositor/main.c 40*4882a593Smuzhiyunindex 57a52b6..dcfe85b 100644 41*4882a593Smuzhiyun--- a/compositor/main.c 42*4882a593Smuzhiyun+++ b/compositor/main.c 43*4882a593Smuzhiyun@@ -2326,7 +2326,7 @@ drm_head_prepare_enable(struct wet_compositor *wet, 44*4882a593Smuzhiyun char *output_name = NULL; 45*4882a593Smuzhiyun char *mode = NULL; 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun- section = drm_config_find_controlling_output_section(wet->config, name); 48*4882a593Smuzhiyun+ section = head->section; 49*4882a593Smuzhiyun if (section) { 50*4882a593Smuzhiyun /* skip outputs that are explicitly off, or non-desktop and not 51*4882a593Smuzhiyun * explicitly enabled. The backend turns them off automatically. 52*4882a593Smuzhiyun@@ -2356,11 +2356,10 @@ static bool 53*4882a593Smuzhiyun drm_head_should_force_enable(struct wet_compositor *wet, 54*4882a593Smuzhiyun struct weston_head *head) 55*4882a593Smuzhiyun { 56*4882a593Smuzhiyun- const char *name = weston_head_get_name(head); 57*4882a593Smuzhiyun struct weston_config_section *section; 58*4882a593Smuzhiyun bool force; 59*4882a593Smuzhiyun 60*4882a593Smuzhiyun- section = drm_config_find_controlling_output_section(wet->config, name); 61*4882a593Smuzhiyun+ section = head->section; 62*4882a593Smuzhiyun if (!section) 63*4882a593Smuzhiyun return false; 64*4882a593Smuzhiyun 65*4882a593Smuzhiyun@@ -2551,6 +2550,21 @@ drm_head_disable(struct weston_head *head) 66*4882a593Smuzhiyun wet_output_destroy(output); 67*4882a593Smuzhiyun } 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun+static bool 70*4882a593Smuzhiyun+drm_head_update_output_section(struct weston_head *head) 71*4882a593Smuzhiyun+{ 72*4882a593Smuzhiyun+ struct weston_compositor *compositor = head->compositor; 73*4882a593Smuzhiyun+ struct wet_compositor *wet = to_wet_compositor(compositor); 74*4882a593Smuzhiyun+ const char *name = weston_head_get_name(head); 75*4882a593Smuzhiyun+ 76*4882a593Smuzhiyun+ if (head->section) 77*4882a593Smuzhiyun+ return true; 78*4882a593Smuzhiyun+ 79*4882a593Smuzhiyun+ head->section = 80*4882a593Smuzhiyun+ drm_config_find_controlling_output_section(wet->config, name); 81*4882a593Smuzhiyun+ return !!head->section; 82*4882a593Smuzhiyun+} 83*4882a593Smuzhiyun+ 84*4882a593Smuzhiyun static void 85*4882a593Smuzhiyun drm_heads_changed(struct wl_listener *listener, void *arg) 86*4882a593Smuzhiyun { 87*4882a593Smuzhiyun@@ -2566,6 +2580,8 @@ drm_heads_changed(struct wl_listener *listener, void *arg) 88*4882a593Smuzhiyun * output. 89*4882a593Smuzhiyun */ 90*4882a593Smuzhiyun while ((head = weston_compositor_iterate_heads(compositor, head))) { 91*4882a593Smuzhiyun+ drm_head_update_output_section(head); 92*4882a593Smuzhiyun+ 93*4882a593Smuzhiyun connected = weston_head_is_connected(head); 94*4882a593Smuzhiyun enabled = weston_head_is_enabled(head); 95*4882a593Smuzhiyun changed = weston_head_is_device_changed(head); 96*4882a593Smuzhiyundiff --git a/desktop-shell/shell.c b/desktop-shell/shell.c 97*4882a593Smuzhiyunindex 79e20ad..89ea491 100644 98*4882a593Smuzhiyun--- a/desktop-shell/shell.c 99*4882a593Smuzhiyun+++ b/desktop-shell/shell.c 100*4882a593Smuzhiyun@@ -3550,6 +3550,9 @@ shell_fade_done_for_output(struct weston_view_animation *animation, void *data) 101*4882a593Smuzhiyun struct shell_output *shell_output = data; 102*4882a593Smuzhiyun struct desktop_shell *shell = shell_output->shell; 103*4882a593Smuzhiyun 104*4882a593Smuzhiyun+ if (!shell_output->fade.curtain) 105*4882a593Smuzhiyun+ return; 106*4882a593Smuzhiyun+ 107*4882a593Smuzhiyun shell_output->fade.animation = NULL; 108*4882a593Smuzhiyun switch (shell_output->fade.type) { 109*4882a593Smuzhiyun case FADE_IN: 110*4882a593Smuzhiyun@@ -4334,8 +4337,12 @@ shell_output_destroy(struct shell_output *shell_output) 111*4882a593Smuzhiyun shell_output->fade.animation = NULL; 112*4882a593Smuzhiyun } 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun- if (shell_output->fade.curtain) 115*4882a593Smuzhiyun- weston_curtain_destroy(shell_output->fade.curtain); 116*4882a593Smuzhiyun+ if (shell_output->fade.curtain) { 117*4882a593Smuzhiyun+ struct weston_curtain *curtain = shell_output->fade.curtain; 118*4882a593Smuzhiyun+ 119*4882a593Smuzhiyun+ shell_output->fade.curtain = NULL; 120*4882a593Smuzhiyun+ weston_curtain_destroy(curtain); 121*4882a593Smuzhiyun+ } 122*4882a593Smuzhiyun 123*4882a593Smuzhiyun if (shell_output->fade.startup_timer) 124*4882a593Smuzhiyun wl_event_source_remove(shell_output->fade.startup_timer); 125*4882a593Smuzhiyun@@ -4438,12 +4445,25 @@ handle_output_move_layer(struct desktop_shell *shell, 126*4882a593Smuzhiyun static void 127*4882a593Smuzhiyun handle_output_move(struct wl_listener *listener, void *data) 128*4882a593Smuzhiyun { 129*4882a593Smuzhiyun+ struct weston_output *output = data; 130*4882a593Smuzhiyun+ struct weston_compositor *compositor = output->compositor; 131*4882a593Smuzhiyun struct desktop_shell *shell; 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun shell = container_of(listener, struct desktop_shell, 134*4882a593Smuzhiyun output_move_listener); 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun- shell_for_each_layer(shell, handle_output_move_layer, data); 137*4882a593Smuzhiyun+ if (shell->lock_surface) 138*4882a593Smuzhiyun+ shell->lock_surface->committed(shell->lock_surface, 0, 0); 139*4882a593Smuzhiyun+ 140*4882a593Smuzhiyun+ /* Only move normal layers for non-default output */ 141*4882a593Smuzhiyun+ if (output != get_default_output(compositor)) { 142*4882a593Smuzhiyun+ shell_for_each_layer(shell, handle_output_move_layer, data); 143*4882a593Smuzhiyun+ return; 144*4882a593Smuzhiyun+ } 145*4882a593Smuzhiyun+ 146*4882a593Smuzhiyun+ handle_output_move_layer(shell, &shell->lock_layer, data); 147*4882a593Smuzhiyun+ handle_output_move_layer(shell, &shell->background_layer, data); 148*4882a593Smuzhiyun+ handle_output_move_layer(shell, &shell->panel_layer, data); 149*4882a593Smuzhiyun } 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun static void 152*4882a593Smuzhiyundiff --git a/include/libweston/libweston.h b/include/libweston/libweston.h 153*4882a593Smuzhiyunindex 984d5f3..d35963f 100644 154*4882a593Smuzhiyun--- a/include/libweston/libweston.h 155*4882a593Smuzhiyun+++ b/include/libweston/libweston.h 156*4882a593Smuzhiyun@@ -399,6 +399,8 @@ struct weston_head { 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun /** Opaque pointer used by backends to identify heads as theirs */ 159*4882a593Smuzhiyun const void *backend_id; 160*4882a593Smuzhiyun+ 161*4882a593Smuzhiyun+ struct weston_config_section *section; /**< config section **/ 162*4882a593Smuzhiyun }; 163*4882a593Smuzhiyun 164*4882a593Smuzhiyun /** Output properties derived from its color characteristics and profile 165*4882a593Smuzhiyundiff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h 166*4882a593Smuzhiyunindex f4b8ed8..ec8bf0e 100644 167*4882a593Smuzhiyun--- a/libweston/backend-drm/drm-internal.h 168*4882a593Smuzhiyun+++ b/libweston/backend-drm/drm-internal.h 169*4882a593Smuzhiyun@@ -110,6 +110,10 @@ 170*4882a593Smuzhiyun 171*4882a593Smuzhiyun #define MAX_CLONED_CONNECTORS 4 172*4882a593Smuzhiyun 173*4882a593Smuzhiyun+/* Min duration between drm outputs update requests, to avoid glith */ 174*4882a593Smuzhiyun+#define DRM_MIN_UPDATE_MS 1000 175*4882a593Smuzhiyun+ 176*4882a593Smuzhiyun+#define DRM_RESIZE_FREEZE_MS 600 177*4882a593Smuzhiyun 178*4882a593Smuzhiyun /** 179*4882a593Smuzhiyun * Represents the values of an enum-type KMS property 180*4882a593Smuzhiyun@@ -268,6 +272,7 @@ struct drm_device { 181*4882a593Smuzhiyun int fd; 182*4882a593Smuzhiyun char *filename; 183*4882a593Smuzhiyun dev_t devnum; 184*4882a593Smuzhiyun+ char *syspath; 185*4882a593Smuzhiyun } drm; 186*4882a593Smuzhiyun 187*4882a593Smuzhiyun /* drm_crtc::link */ 188*4882a593Smuzhiyun@@ -302,6 +307,10 @@ struct drm_device { 189*4882a593Smuzhiyun int min_height, max_height; 190*4882a593Smuzhiyun }; 191*4882a593Smuzhiyun 192*4882a593Smuzhiyun+struct drm_head; 193*4882a593Smuzhiyun+struct drm_backend; 194*4882a593Smuzhiyun+typedef bool (*drm_head_match_t) (struct drm_backend *, struct drm_head *); 195*4882a593Smuzhiyun+ 196*4882a593Smuzhiyun struct drm_backend { 197*4882a593Smuzhiyun struct weston_backend base; 198*4882a593Smuzhiyun struct weston_compositor *compositor; 199*4882a593Smuzhiyun@@ -327,6 +336,19 @@ struct drm_backend { 200*4882a593Smuzhiyun bool shutting_down; 201*4882a593Smuzhiyun 202*4882a593Smuzhiyun struct weston_log_scope *debug; 203*4882a593Smuzhiyun+ 204*4882a593Smuzhiyun+ struct wl_event_source *hotplug_timer; 205*4882a593Smuzhiyun+ bool pending_update; 206*4882a593Smuzhiyun+ int64_t last_update_ms; 207*4882a593Smuzhiyun+ int64_t last_resize_ms; 208*4882a593Smuzhiyun+ int64_t resize_freeze_ms; 209*4882a593Smuzhiyun+ 210*4882a593Smuzhiyun+ bool single_head; 211*4882a593Smuzhiyun+ bool head_fallback; 212*4882a593Smuzhiyun+ bool head_fallback_all; 213*4882a593Smuzhiyun+ drm_head_match_t *head_matches; 214*4882a593Smuzhiyun+ struct drm_head *primary_head; 215*4882a593Smuzhiyun+ struct wl_listener output_create_listener; 216*4882a593Smuzhiyun }; 217*4882a593Smuzhiyun 218*4882a593Smuzhiyun struct drm_mode { 219*4882a593Smuzhiyun@@ -589,6 +611,8 @@ struct drm_output { 220*4882a593Smuzhiyun void (*virtual_destroy)(struct weston_output *base); 221*4882a593Smuzhiyun 222*4882a593Smuzhiyun submit_frame_cb virtual_submit_frame; 223*4882a593Smuzhiyun+ 224*4882a593Smuzhiyun+ bool state_invalid; 225*4882a593Smuzhiyun }; 226*4882a593Smuzhiyun 227*4882a593Smuzhiyun void 228*4882a593Smuzhiyundiff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c 229*4882a593Smuzhiyunindex 711ed5b..f5ac1b6 100644 230*4882a593Smuzhiyun--- a/libweston/backend-drm/drm.c 231*4882a593Smuzhiyun+++ b/libweston/backend-drm/drm.c 232*4882a593Smuzhiyun@@ -30,6 +30,7 @@ 233*4882a593Smuzhiyun #include "config.h" 234*4882a593Smuzhiyun 235*4882a593Smuzhiyun #include <errno.h> 236*4882a593Smuzhiyun+#include <stdio.h> 237*4882a593Smuzhiyun #include <stdint.h> 238*4882a593Smuzhiyun #include <stdlib.h> 239*4882a593Smuzhiyun #include <ctype.h> 240*4882a593Smuzhiyun@@ -47,6 +48,7 @@ 241*4882a593Smuzhiyun 242*4882a593Smuzhiyun #include <libudev.h> 243*4882a593Smuzhiyun 244*4882a593Smuzhiyun+#include <libweston/config-parser.h> 245*4882a593Smuzhiyun #include <libweston/libweston.h> 246*4882a593Smuzhiyun #include <libweston/backend-drm.h> 247*4882a593Smuzhiyun #include <libweston/weston-log.h> 248*4882a593Smuzhiyun@@ -68,6 +70,43 @@ 249*4882a593Smuzhiyun 250*4882a593Smuzhiyun static const char default_seat[] = "seat0"; 251*4882a593Smuzhiyun 252*4882a593Smuzhiyun+static inline bool 253*4882a593Smuzhiyun+drm_head_is_external(struct drm_head *head) 254*4882a593Smuzhiyun+{ 255*4882a593Smuzhiyun+ drmModeConnector *conn = head->connector.conn; 256*4882a593Smuzhiyun+ switch (conn->connector_type) { 257*4882a593Smuzhiyun+ case DRM_MODE_CONNECTOR_LVDS: 258*4882a593Smuzhiyun+ case DRM_MODE_CONNECTOR_eDP: 259*4882a593Smuzhiyun+#ifdef DRM_MODE_CONNECTOR_DSI 260*4882a593Smuzhiyun+ case DRM_MODE_CONNECTOR_DSI: 261*4882a593Smuzhiyun+#endif 262*4882a593Smuzhiyun+ return false; 263*4882a593Smuzhiyun+ default: 264*4882a593Smuzhiyun+ return true; 265*4882a593Smuzhiyun+ } 266*4882a593Smuzhiyun+}; 267*4882a593Smuzhiyun+ 268*4882a593Smuzhiyun+static void 269*4882a593Smuzhiyun+drm_backend_update_outputs(struct drm_backend *b) 270*4882a593Smuzhiyun+{ 271*4882a593Smuzhiyun+ struct weston_output *primary; 272*4882a593Smuzhiyun+ 273*4882a593Smuzhiyun+ if (!b->primary_head) 274*4882a593Smuzhiyun+ return; 275*4882a593Smuzhiyun+ 276*4882a593Smuzhiyun+ primary = b->primary_head->base.output; 277*4882a593Smuzhiyun+ if (!primary) 278*4882a593Smuzhiyun+ return; 279*4882a593Smuzhiyun+ 280*4882a593Smuzhiyun+ wl_list_remove(&primary->link); 281*4882a593Smuzhiyun+ wl_list_insert(&b->compositor->output_list, &primary->link); 282*4882a593Smuzhiyun+ 283*4882a593Smuzhiyun+ /* Reflow outputs */ 284*4882a593Smuzhiyun+ weston_compositor_reflow_outputs(b->compositor); 285*4882a593Smuzhiyun+ 286*4882a593Smuzhiyun+ weston_compositor_damage_all(b->compositor); 287*4882a593Smuzhiyun+} 288*4882a593Smuzhiyun+ 289*4882a593Smuzhiyun static void 290*4882a593Smuzhiyun drm_backend_create_faked_zpos(struct drm_backend *b) 291*4882a593Smuzhiyun { 292*4882a593Smuzhiyun@@ -464,18 +503,36 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) 293*4882a593Smuzhiyun struct drm_plane_state *scanout_state; 294*4882a593Smuzhiyun struct drm_pending_state *pending_state; 295*4882a593Smuzhiyun struct drm_device *device; 296*4882a593Smuzhiyun+ struct drm_backend *b; 297*4882a593Smuzhiyun+ struct timespec now; 298*4882a593Smuzhiyun+ int64_t now_ms; 299*4882a593Smuzhiyun 300*4882a593Smuzhiyun assert(output); 301*4882a593Smuzhiyun assert(!output->virtual); 302*4882a593Smuzhiyun 303*4882a593Smuzhiyun device = output->device; 304*4882a593Smuzhiyun pending_state = device->repaint_data; 305*4882a593Smuzhiyun+ b = device->backend; 306*4882a593Smuzhiyun 307*4882a593Smuzhiyun if (output->disable_pending || output->destroy_pending) 308*4882a593Smuzhiyun goto err; 309*4882a593Smuzhiyun 310*4882a593Smuzhiyun assert(!output->state_last); 311*4882a593Smuzhiyun 312*4882a593Smuzhiyun+ weston_compositor_read_presentation_clock(b->compositor, &now); 313*4882a593Smuzhiyun+ now_ms = timespec_to_msec(&now); 314*4882a593Smuzhiyun+ if (now_ms < b->last_resize_ms + DRM_RESIZE_FREEZE_MS) { 315*4882a593Smuzhiyun+ /* Resize fullscreen/maxmium views(not always success) */ 316*4882a593Smuzhiyun+ if (now_ms < b->last_resize_ms + DRM_RESIZE_FREEZE_MS) 317*4882a593Smuzhiyun+ wl_signal_emit(&b->compositor->output_resized_signal, 318*4882a593Smuzhiyun+ output); 319*4882a593Smuzhiyun+ 320*4882a593Smuzhiyun+ weston_output_damage(output_base); 321*4882a593Smuzhiyun+ weston_output_finish_frame(output_base, NULL, 322*4882a593Smuzhiyun+ WP_PRESENTATION_FEEDBACK_INVALID); 323*4882a593Smuzhiyun+ return 0; 324*4882a593Smuzhiyun+ } 325*4882a593Smuzhiyun+ 326*4882a593Smuzhiyun /* If planes have been disabled in the core, we might not have 327*4882a593Smuzhiyun * hit assign_planes at all, so might not have valid output state 328*4882a593Smuzhiyun * here. */ 329*4882a593Smuzhiyun@@ -504,7 +561,7 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) 330*4882a593Smuzhiyun 331*4882a593Smuzhiyun err: 332*4882a593Smuzhiyun drm_output_state_free(state); 333*4882a593Smuzhiyun- return -1; 334*4882a593Smuzhiyun+ return 0; 335*4882a593Smuzhiyun } 336*4882a593Smuzhiyun 337*4882a593Smuzhiyun /* Determine the type of vblank synchronization to use for the output. 338*4882a593Smuzhiyun@@ -743,6 +800,7 @@ drm_output_apply_mode(struct drm_output *output) 339*4882a593Smuzhiyun * content. 340*4882a593Smuzhiyun */ 341*4882a593Smuzhiyun device->state_invalid = true; 342*4882a593Smuzhiyun+ output->state_invalid = true; 343*4882a593Smuzhiyun 344*4882a593Smuzhiyun if (b->use_pixman) { 345*4882a593Smuzhiyun drm_output_fini_pixman(output); 346*4882a593Smuzhiyun@@ -1322,6 +1380,7 @@ drm_output_attach_head(struct weston_output *output_base, 347*4882a593Smuzhiyun { 348*4882a593Smuzhiyun struct drm_backend *b = to_drm_backend(output_base->compositor); 349*4882a593Smuzhiyun struct drm_device *device = b->drm; 350*4882a593Smuzhiyun+ struct drm_output *output = to_drm_output(output_base); 351*4882a593Smuzhiyun 352*4882a593Smuzhiyun if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS) 353*4882a593Smuzhiyun return -1; 354*4882a593Smuzhiyun@@ -1339,6 +1398,7 @@ drm_output_attach_head(struct weston_output *output_base, 355*4882a593Smuzhiyun * will not clear the flag before this output is updated? 356*4882a593Smuzhiyun */ 357*4882a593Smuzhiyun device->state_invalid = true; 358*4882a593Smuzhiyun+ output->state_invalid = true; 359*4882a593Smuzhiyun 360*4882a593Smuzhiyun weston_output_schedule_repaint(output_base); 361*4882a593Smuzhiyun 362*4882a593Smuzhiyun@@ -1351,6 +1411,7 @@ drm_output_detach_head(struct weston_output *output_base, 363*4882a593Smuzhiyun { 364*4882a593Smuzhiyun struct drm_backend *b = to_drm_backend(output_base->compositor); 365*4882a593Smuzhiyun struct drm_device *device = b->drm; 366*4882a593Smuzhiyun+ struct drm_output *output = to_drm_output(output_base); 367*4882a593Smuzhiyun 368*4882a593Smuzhiyun if (!output_base->enabled) 369*4882a593Smuzhiyun return; 370*4882a593Smuzhiyun@@ -1359,6 +1420,7 @@ drm_output_detach_head(struct weston_output *output_base, 371*4882a593Smuzhiyun * be driven. */ 372*4882a593Smuzhiyun /* XXX: Ideally we'd do this per-output, not globally. */ 373*4882a593Smuzhiyun device->state_invalid = true; 374*4882a593Smuzhiyun+ output->state_invalid = true; 375*4882a593Smuzhiyun 376*4882a593Smuzhiyun weston_output_schedule_repaint(output_base); 377*4882a593Smuzhiyun } 378*4882a593Smuzhiyun@@ -1917,6 +1979,8 @@ drm_output_enable(struct weston_output *base) 379*4882a593Smuzhiyun output->base.switch_mode = drm_output_switch_mode; 380*4882a593Smuzhiyun output->base.set_gamma = drm_output_set_gamma; 381*4882a593Smuzhiyun 382*4882a593Smuzhiyun+ output->state_invalid = true; 383*4882a593Smuzhiyun+ 384*4882a593Smuzhiyun weston_log("Output %s (crtc %d) video modes:\n", 385*4882a593Smuzhiyun output->base.name, output->crtc->crtc_id); 386*4882a593Smuzhiyun drm_output_print_modes(output); 387*4882a593Smuzhiyun@@ -2278,8 +2342,7 @@ drm_head_create(struct drm_device *device, drmModeConnector *conn, 388*4882a593Smuzhiyun 389*4882a593Smuzhiyun head->backlight = backlight_init(drm_device, conn->connector_type); 390*4882a593Smuzhiyun 391*4882a593Smuzhiyun- if (conn->connector_type == DRM_MODE_CONNECTOR_LVDS || 392*4882a593Smuzhiyun- conn->connector_type == DRM_MODE_CONNECTOR_eDP) 393*4882a593Smuzhiyun+ if (!drm_head_is_external(head)) 394*4882a593Smuzhiyun weston_head_set_internal(&head->base); 395*4882a593Smuzhiyun 396*4882a593Smuzhiyun if (drm_head_read_current_setup(head, device) < 0) { 397*4882a593Smuzhiyun@@ -2447,56 +2510,54 @@ drm_backend_add_connector(struct drm_device *device, drmModeConnector *conn, 398*4882a593Smuzhiyun return ret; 399*4882a593Smuzhiyun } 400*4882a593Smuzhiyun 401*4882a593Smuzhiyun-/** Find all connectors of the fd and create drm_head or drm_writeback objects 402*4882a593Smuzhiyun- * (depending on the type of connector they are) for each of them 403*4882a593Smuzhiyun- * 404*4882a593Smuzhiyun- * These objects are added to the DRM-backend lists of heads and writebacks. 405*4882a593Smuzhiyun- * 406*4882a593Smuzhiyun- * @param device The DRM device structure 407*4882a593Smuzhiyun- * @param drm_device udev device pointer 408*4882a593Smuzhiyun- * @param resources The DRM resources, it is taken with drmModeGetResources 409*4882a593Smuzhiyun- * @return 0 on success, -1 on failure 410*4882a593Smuzhiyun- */ 411*4882a593Smuzhiyun-static int 412*4882a593Smuzhiyun-drm_backend_discover_connectors(struct drm_device *device, 413*4882a593Smuzhiyun- struct udev_device *drm_device, 414*4882a593Smuzhiyun- drmModeRes *resources) 415*4882a593Smuzhiyun+static bool 416*4882a593Smuzhiyun+resources_has_connector(drmModeRes *resources, uint32_t connector_id) 417*4882a593Smuzhiyun { 418*4882a593Smuzhiyun- drmModeConnector *conn; 419*4882a593Smuzhiyun- int i, ret; 420*4882a593Smuzhiyun+ for (int i = 0; i < resources->count_connectors; i++) { 421*4882a593Smuzhiyun+ if (resources->connectors[i] == connector_id) 422*4882a593Smuzhiyun+ return true; 423*4882a593Smuzhiyun+ } 424*4882a593Smuzhiyun 425*4882a593Smuzhiyun- device->min_width = resources->min_width; 426*4882a593Smuzhiyun- device->max_width = resources->max_width; 427*4882a593Smuzhiyun- device->min_height = resources->min_height; 428*4882a593Smuzhiyun- device->max_height = resources->max_height; 429*4882a593Smuzhiyun+ return false; 430*4882a593Smuzhiyun+} 431*4882a593Smuzhiyun 432*4882a593Smuzhiyun- for (i = 0; i < resources->count_connectors; i++) { 433*4882a593Smuzhiyun- uint32_t connector_id = resources->connectors[i]; 434*4882a593Smuzhiyun+/* based on compositor/main.c#drm_head_prepare_enable() */ 435*4882a593Smuzhiyun+static bool 436*4882a593Smuzhiyun+drm_head_is_available(struct weston_head *head) 437*4882a593Smuzhiyun+{ 438*4882a593Smuzhiyun+ struct weston_config_section *section; 439*4882a593Smuzhiyun+ char *mode = NULL; 440*4882a593Smuzhiyun 441*4882a593Smuzhiyun- conn = drmModeGetConnector(device->drm.fd, connector_id); 442*4882a593Smuzhiyun- if (!conn) 443*4882a593Smuzhiyun- continue; 444*4882a593Smuzhiyun+ section = head->section; 445*4882a593Smuzhiyun+ if (!section) 446*4882a593Smuzhiyun+ return true; 447*4882a593Smuzhiyun 448*4882a593Smuzhiyun- ret = drm_backend_add_connector(device, conn, drm_device); 449*4882a593Smuzhiyun- if (ret < 0) 450*4882a593Smuzhiyun- drmModeFreeConnector(conn); 451*4882a593Smuzhiyun+ /* skip outputs that are explicitly off, or non-desktop and not 452*4882a593Smuzhiyun+ * explicitly enabled. 453*4882a593Smuzhiyun+ */ 454*4882a593Smuzhiyun+ weston_config_section_get_string(section, "mode", &mode, NULL); 455*4882a593Smuzhiyun+ if (mode && strcmp(mode, "off") == 0) { 456*4882a593Smuzhiyun+ free(mode); 457*4882a593Smuzhiyun+ return false; 458*4882a593Smuzhiyun } 459*4882a593Smuzhiyun 460*4882a593Smuzhiyun- return 0; 461*4882a593Smuzhiyun+ if (!mode && weston_head_is_non_desktop(head)) 462*4882a593Smuzhiyun+ return false; 463*4882a593Smuzhiyun+ 464*4882a593Smuzhiyun+ free(mode); 465*4882a593Smuzhiyun+ return true; 466*4882a593Smuzhiyun } 467*4882a593Smuzhiyun 468*4882a593Smuzhiyun static bool 469*4882a593Smuzhiyun-resources_has_connector(drmModeRes *resources, uint32_t connector_id) 470*4882a593Smuzhiyun+drm_head_match_fallback(struct drm_backend *b, struct drm_head *head) 471*4882a593Smuzhiyun { 472*4882a593Smuzhiyun- for (int i = 0; i < resources->count_connectors; i++) { 473*4882a593Smuzhiyun- if (resources->connectors[i] == connector_id) 474*4882a593Smuzhiyun- return true; 475*4882a593Smuzhiyun- } 476*4882a593Smuzhiyun+ if (b->head_fallback_all) 477*4882a593Smuzhiyun+ return true; 478*4882a593Smuzhiyun 479*4882a593Smuzhiyun- return false; 480*4882a593Smuzhiyun+ return b->head_fallback && !b->primary_head; 481*4882a593Smuzhiyun } 482*4882a593Smuzhiyun 483*4882a593Smuzhiyun-static void 484*4882a593Smuzhiyun+static int 485*4882a593Smuzhiyun drm_backend_update_connectors(struct drm_device *device, 486*4882a593Smuzhiyun struct udev_device *drm_device) 487*4882a593Smuzhiyun { 488*4882a593Smuzhiyun@@ -2504,17 +2565,24 @@ drm_backend_update_connectors(struct drm_device *device, 489*4882a593Smuzhiyun drmModeRes *resources; 490*4882a593Smuzhiyun drmModeConnector *conn; 491*4882a593Smuzhiyun struct weston_head *base, *base_next; 492*4882a593Smuzhiyun- struct drm_head *head; 493*4882a593Smuzhiyun+ struct drm_head *head, *old_primary_head; 494*4882a593Smuzhiyun struct drm_writeback *writeback, *writeback_next; 495*4882a593Smuzhiyun+ drm_head_match_t *match = b->head_matches; 496*4882a593Smuzhiyun+ struct timespec now; 497*4882a593Smuzhiyun uint32_t connector_id; 498*4882a593Smuzhiyun int i, ret; 499*4882a593Smuzhiyun 500*4882a593Smuzhiyun resources = drmModeGetResources(device->drm.fd); 501*4882a593Smuzhiyun if (!resources) { 502*4882a593Smuzhiyun weston_log("drmModeGetResources failed\n"); 503*4882a593Smuzhiyun- return; 504*4882a593Smuzhiyun+ return -1; 505*4882a593Smuzhiyun } 506*4882a593Smuzhiyun 507*4882a593Smuzhiyun+ device->min_width = resources->min_width; 508*4882a593Smuzhiyun+ device->max_width = resources->max_width; 509*4882a593Smuzhiyun+ device->min_height = resources->min_height; 510*4882a593Smuzhiyun+ device->max_height = resources->max_height; 511*4882a593Smuzhiyun+ 512*4882a593Smuzhiyun /* collect new connectors that have appeared, e.g. MST */ 513*4882a593Smuzhiyun for (i = 0; i < resources->count_connectors; i++) { 514*4882a593Smuzhiyun connector_id = resources->connectors[i]; 515*4882a593Smuzhiyun@@ -2576,6 +2644,65 @@ drm_backend_update_connectors(struct drm_device *device, 516*4882a593Smuzhiyun } 517*4882a593Smuzhiyun 518*4882a593Smuzhiyun drmModeFreeResources(resources); 519*4882a593Smuzhiyun+ 520*4882a593Smuzhiyun+ old_primary_head = b->primary_head; 521*4882a593Smuzhiyun+ b->primary_head = NULL; 522*4882a593Smuzhiyun+ 523*4882a593Smuzhiyun+ wl_list_for_each_safe(base, base_next, 524*4882a593Smuzhiyun+ &b->compositor->head_list, compositor_link) 525*4882a593Smuzhiyun+ weston_head_set_connection_status(base, false); 526*4882a593Smuzhiyun+ 527*4882a593Smuzhiyun+ /* Re-connect matched heads and find primary head */ 528*4882a593Smuzhiyun+ while (*match) { 529*4882a593Smuzhiyun+ wl_list_for_each_safe(base, base_next, 530*4882a593Smuzhiyun+ &b->compositor->head_list, 531*4882a593Smuzhiyun+ compositor_link) { 532*4882a593Smuzhiyun+ drmModeConnector *conn; 533*4882a593Smuzhiyun+ 534*4882a593Smuzhiyun+ if (!drm_head_is_available(base)) 535*4882a593Smuzhiyun+ continue; 536*4882a593Smuzhiyun+ 537*4882a593Smuzhiyun+ head = to_drm_head(base); 538*4882a593Smuzhiyun+ conn = head->connector.conn; 539*4882a593Smuzhiyun+ 540*4882a593Smuzhiyun+ if (conn->connection != DRM_MODE_CONNECTED || 541*4882a593Smuzhiyun+ !(*match)(b, head)) 542*4882a593Smuzhiyun+ continue; 543*4882a593Smuzhiyun+ 544*4882a593Smuzhiyun+ weston_head_set_connection_status(base, true); 545*4882a593Smuzhiyun+ 546*4882a593Smuzhiyun+ if (!b->primary_head) { 547*4882a593Smuzhiyun+ b->primary_head = head; 548*4882a593Smuzhiyun+ 549*4882a593Smuzhiyun+ /* Done the single-head match */ 550*4882a593Smuzhiyun+ if (b->single_head) 551*4882a593Smuzhiyun+ goto match_done; 552*4882a593Smuzhiyun+ } 553*4882a593Smuzhiyun+ } 554*4882a593Smuzhiyun+ 555*4882a593Smuzhiyun+ /* Done the fallback match */ 556*4882a593Smuzhiyun+ if (*match == drm_head_match_fallback) 557*4882a593Smuzhiyun+ goto match_done; 558*4882a593Smuzhiyun+ 559*4882a593Smuzhiyun+ match++; 560*4882a593Smuzhiyun+ 561*4882a593Smuzhiyun+ /* Try the fallback match */ 562*4882a593Smuzhiyun+ if (!match && !b->primary_head) 563*4882a593Smuzhiyun+ *match = drm_head_match_fallback; 564*4882a593Smuzhiyun+ } 565*4882a593Smuzhiyun+match_done: 566*4882a593Smuzhiyun+ 567*4882a593Smuzhiyun+ drm_backend_update_outputs(b); 568*4882a593Smuzhiyun+ 569*4882a593Smuzhiyun+ weston_compositor_read_presentation_clock(b->compositor, &now); 570*4882a593Smuzhiyun+ b->last_update_ms = timespec_to_msec(&now); 571*4882a593Smuzhiyun+ 572*4882a593Smuzhiyun+ /* Assume primary output's size changed */ 573*4882a593Smuzhiyun+ if (b->primary_head && old_primary_head && 574*4882a593Smuzhiyun+ b->primary_head != old_primary_head) 575*4882a593Smuzhiyun+ b->last_resize_ms = b->last_update_ms; 576*4882a593Smuzhiyun+ 577*4882a593Smuzhiyun+ return 0; 578*4882a593Smuzhiyun } 579*4882a593Smuzhiyun 580*4882a593Smuzhiyun static enum wdrm_connector_property 581*4882a593Smuzhiyun@@ -2666,6 +2793,50 @@ udev_event_is_conn_prop_change(struct drm_backend *b, 582*4882a593Smuzhiyun return 1; 583*4882a593Smuzhiyun } 584*4882a593Smuzhiyun 585*4882a593Smuzhiyun+static void 586*4882a593Smuzhiyun+udev_hotplug_event(struct drm_device *device, struct udev_device *udev_device) 587*4882a593Smuzhiyun+{ 588*4882a593Smuzhiyun+ struct drm_backend *b = device->backend; 589*4882a593Smuzhiyun+ struct timespec now; 590*4882a593Smuzhiyun+ int64_t now_ms, next_ms; 591*4882a593Smuzhiyun+ 592*4882a593Smuzhiyun+ weston_compositor_read_presentation_clock(b->compositor, &now); 593*4882a593Smuzhiyun+ now_ms = timespec_to_msec(&now); 594*4882a593Smuzhiyun+ 595*4882a593Smuzhiyun+ /* Already have a pending request */ 596*4882a593Smuzhiyun+ if (b->pending_update) 597*4882a593Smuzhiyun+ return; 598*4882a593Smuzhiyun+ 599*4882a593Smuzhiyun+ next_ms = b->last_update_ms + DRM_MIN_UPDATE_MS; 600*4882a593Smuzhiyun+ if (next_ms <= now_ms) { 601*4882a593Smuzhiyun+ /* Long enough to trigger a new request */ 602*4882a593Smuzhiyun+ drm_backend_update_connectors(device, udev_device); 603*4882a593Smuzhiyun+ } else { 604*4882a593Smuzhiyun+ /* Too close to the last request, schedule a new one */ 605*4882a593Smuzhiyun+ b->pending_update = true; 606*4882a593Smuzhiyun+ wl_event_source_timer_update(b->hotplug_timer, 607*4882a593Smuzhiyun+ next_ms - now_ms); 608*4882a593Smuzhiyun+ } 609*4882a593Smuzhiyun+} 610*4882a593Smuzhiyun+ 611*4882a593Smuzhiyun+static int 612*4882a593Smuzhiyun+hotplug_timer_handler(void *data) 613*4882a593Smuzhiyun+{ 614*4882a593Smuzhiyun+ struct drm_device *device = data; 615*4882a593Smuzhiyun+ struct drm_backend *b = device->backend; 616*4882a593Smuzhiyun+ struct udev_device *udev_device; 617*4882a593Smuzhiyun+ struct udev *udev; 618*4882a593Smuzhiyun+ 619*4882a593Smuzhiyun+ udev = udev_monitor_get_udev(b->udev_monitor); 620*4882a593Smuzhiyun+ udev_device = udev_device_new_from_syspath(udev, device->drm.syspath); 621*4882a593Smuzhiyun+ 622*4882a593Smuzhiyun+ drm_backend_update_connectors(device, udev_device); 623*4882a593Smuzhiyun+ b->pending_update = false; 624*4882a593Smuzhiyun+ 625*4882a593Smuzhiyun+ udev_device_unref(udev_device); 626*4882a593Smuzhiyun+ return 0; 627*4882a593Smuzhiyun+} 628*4882a593Smuzhiyun+ 629*4882a593Smuzhiyun static int 630*4882a593Smuzhiyun udev_drm_event(int fd, uint32_t mask, void *data) 631*4882a593Smuzhiyun { 632*4882a593Smuzhiyun@@ -2679,7 +2850,7 @@ udev_drm_event(int fd, uint32_t mask, void *data) 633*4882a593Smuzhiyun if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id)) 634*4882a593Smuzhiyun drm_backend_update_conn_props(b, conn_id, prop_id); 635*4882a593Smuzhiyun else 636*4882a593Smuzhiyun- drm_backend_update_connectors(b->drm, event); 637*4882a593Smuzhiyun+ udev_hotplug_event(b->drm, event); 638*4882a593Smuzhiyun } 639*4882a593Smuzhiyun 640*4882a593Smuzhiyun udev_device_unref(event); 641*4882a593Smuzhiyun@@ -2698,6 +2869,7 @@ drm_destroy(struct weston_compositor *ec) 642*4882a593Smuzhiyun 643*4882a593Smuzhiyun udev_input_destroy(&b->input); 644*4882a593Smuzhiyun 645*4882a593Smuzhiyun+ wl_event_source_remove(b->hotplug_timer); 646*4882a593Smuzhiyun wl_event_source_remove(b->udev_drm_source); 647*4882a593Smuzhiyun wl_event_source_remove(b->drm_source); 648*4882a593Smuzhiyun 649*4882a593Smuzhiyun@@ -2750,6 +2922,10 @@ session_notify(struct wl_listener *listener, void *data) 650*4882a593Smuzhiyun weston_compositor_wake(compositor); 651*4882a593Smuzhiyun weston_compositor_damage_all(compositor); 652*4882a593Smuzhiyun device->state_invalid = true; 653*4882a593Smuzhiyun+ 654*4882a593Smuzhiyun+ wl_list_for_each(output, &compositor->output_list, link) 655*4882a593Smuzhiyun+ to_drm_output(output)->state_invalid = true; 656*4882a593Smuzhiyun+ 657*4882a593Smuzhiyun udev_input_enable(&b->input); 658*4882a593Smuzhiyun } else { 659*4882a593Smuzhiyun weston_log("deactivating session\n"); 660*4882a593Smuzhiyun@@ -3106,6 +3282,14 @@ recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time, 661*4882a593Smuzhiyun } 662*4882a593Smuzhiyun #endif 663*4882a593Smuzhiyun 664*4882a593Smuzhiyun+static void 665*4882a593Smuzhiyun+output_create_notify(struct wl_listener *listener, void *data) 666*4882a593Smuzhiyun+{ 667*4882a593Smuzhiyun+ struct drm_backend *b = container_of(listener, struct drm_backend, 668*4882a593Smuzhiyun+ output_create_listener); 669*4882a593Smuzhiyun+ 670*4882a593Smuzhiyun+ drm_backend_update_outputs(b); 671*4882a593Smuzhiyun+} 672*4882a593Smuzhiyun 673*4882a593Smuzhiyun static const struct weston_drm_output_api api = { 674*4882a593Smuzhiyun drm_output_set_mode, 675*4882a593Smuzhiyun@@ -3114,6 +3298,63 @@ static const struct weston_drm_output_api api = { 676*4882a593Smuzhiyun drm_output_set_max_bpc, 677*4882a593Smuzhiyun }; 678*4882a593Smuzhiyun 679*4882a593Smuzhiyun+enum drm_head_mode { 680*4882a593Smuzhiyun+ DRM_HEAD_MODE_DEFAULT, 681*4882a593Smuzhiyun+ DRM_HEAD_MODE_PRIMARY, 682*4882a593Smuzhiyun+ DRM_HEAD_MODE_INTERNAL, 683*4882a593Smuzhiyun+ DRM_HEAD_MODE_EXTERNAL, 684*4882a593Smuzhiyun+ DRM_HEAD_MODE_EXTERNAL_DUAL, 685*4882a593Smuzhiyun+}; 686*4882a593Smuzhiyun+ 687*4882a593Smuzhiyun+static bool 688*4882a593Smuzhiyun+drm_head_match_primary(struct drm_backend *b, struct drm_head *head) 689*4882a593Smuzhiyun+{ 690*4882a593Smuzhiyun+ const char *buf = getenv("WESTON_DRM_PRIMARY"); 691*4882a593Smuzhiyun+ return buf && !strcmp(buf, head->base.name); 692*4882a593Smuzhiyun+} 693*4882a593Smuzhiyun+ 694*4882a593Smuzhiyun+static bool 695*4882a593Smuzhiyun+drm_head_match_external(struct drm_backend *b, struct drm_head *head) 696*4882a593Smuzhiyun+{ 697*4882a593Smuzhiyun+ return drm_head_is_external(head); 698*4882a593Smuzhiyun+} 699*4882a593Smuzhiyun+ 700*4882a593Smuzhiyun+static bool 701*4882a593Smuzhiyun+drm_head_match_internal(struct drm_backend *b, struct drm_head *head) 702*4882a593Smuzhiyun+{ 703*4882a593Smuzhiyun+ return !drm_head_is_external(head); 704*4882a593Smuzhiyun+} 705*4882a593Smuzhiyun+ 706*4882a593Smuzhiyun+#define DRM_HEAD_MAX_MATCHES 5 707*4882a593Smuzhiyun+static drm_head_match_t drm_head_matches[][DRM_HEAD_MAX_MATCHES] = { 708*4882a593Smuzhiyun+ [DRM_HEAD_MODE_DEFAULT] = { 709*4882a593Smuzhiyun+ drm_head_match_primary, 710*4882a593Smuzhiyun+ drm_head_match_internal, 711*4882a593Smuzhiyun+ drm_head_match_external, 712*4882a593Smuzhiyun+ NULL, 713*4882a593Smuzhiyun+ }, 714*4882a593Smuzhiyun+ [DRM_HEAD_MODE_PRIMARY] = { 715*4882a593Smuzhiyun+ drm_head_match_primary, 716*4882a593Smuzhiyun+ NULL, 717*4882a593Smuzhiyun+ }, 718*4882a593Smuzhiyun+ [DRM_HEAD_MODE_INTERNAL] = { 719*4882a593Smuzhiyun+ drm_head_match_primary, 720*4882a593Smuzhiyun+ drm_head_match_internal, 721*4882a593Smuzhiyun+ NULL, 722*4882a593Smuzhiyun+ }, 723*4882a593Smuzhiyun+ [DRM_HEAD_MODE_EXTERNAL] = { 724*4882a593Smuzhiyun+ drm_head_match_primary, 725*4882a593Smuzhiyun+ drm_head_match_external, 726*4882a593Smuzhiyun+ NULL, 727*4882a593Smuzhiyun+ }, 728*4882a593Smuzhiyun+ [DRM_HEAD_MODE_EXTERNAL_DUAL] = { 729*4882a593Smuzhiyun+ drm_head_match_primary, 730*4882a593Smuzhiyun+ drm_head_match_external, 731*4882a593Smuzhiyun+ drm_head_match_internal, 732*4882a593Smuzhiyun+ NULL, 733*4882a593Smuzhiyun+ }, 734*4882a593Smuzhiyun+}; 735*4882a593Smuzhiyun+ 736*4882a593Smuzhiyun static struct drm_backend * 737*4882a593Smuzhiyun drm_backend_create(struct weston_compositor *compositor, 738*4882a593Smuzhiyun struct weston_drm_backend_config *config) 739*4882a593Smuzhiyun@@ -3125,7 +3366,9 @@ drm_backend_create(struct weston_compositor *compositor, 740*4882a593Smuzhiyun const char *seat_id = default_seat; 741*4882a593Smuzhiyun const char *session_seat; 742*4882a593Smuzhiyun struct weston_drm_format_array *scanout_formats; 743*4882a593Smuzhiyun+ enum drm_head_mode head_mode = DRM_HEAD_MODE_DEFAULT; 744*4882a593Smuzhiyun drmModeRes *res; 745*4882a593Smuzhiyun+ char *buf; 746*4882a593Smuzhiyun int ret; 747*4882a593Smuzhiyun 748*4882a593Smuzhiyun session_seat = getenv("XDG_SEAT"); 749*4882a593Smuzhiyun@@ -3141,6 +3384,48 @@ drm_backend_create(struct weston_compositor *compositor, 750*4882a593Smuzhiyun if (b == NULL) 751*4882a593Smuzhiyun return NULL; 752*4882a593Smuzhiyun 753*4882a593Smuzhiyun+ buf = getenv("WESTON_DRM_SINGLE_HEAD"); 754*4882a593Smuzhiyun+ if (buf && buf[0] == '1') 755*4882a593Smuzhiyun+ b->single_head = true; 756*4882a593Smuzhiyun+ 757*4882a593Smuzhiyun+ buf = getenv("WESTON_DRM_HEAD_FALLBACK"); 758*4882a593Smuzhiyun+ if (buf && buf[0] == '1') 759*4882a593Smuzhiyun+ b->head_fallback = true; 760*4882a593Smuzhiyun+ 761*4882a593Smuzhiyun+ buf = getenv("WESTON_DRM_HEAD_FALLBACK_ALL"); 762*4882a593Smuzhiyun+ if (buf && buf[0] == '1') 763*4882a593Smuzhiyun+ b->head_fallback_all = true; 764*4882a593Smuzhiyun+ 765*4882a593Smuzhiyun+ buf = getenv("WESTON_DRM_PREFER_EXTERNAL"); 766*4882a593Smuzhiyun+ if (buf && buf[0] == '1') { 767*4882a593Smuzhiyun+ head_mode = DRM_HEAD_MODE_EXTERNAL; 768*4882a593Smuzhiyun+ b->head_fallback = true; 769*4882a593Smuzhiyun+ } 770*4882a593Smuzhiyun+ 771*4882a593Smuzhiyun+ buf = getenv("WESTON_DRM_PREFER_EXTERNAL_DUAL"); 772*4882a593Smuzhiyun+ if (buf && buf[0] == '1') 773*4882a593Smuzhiyun+ head_mode = DRM_HEAD_MODE_EXTERNAL_DUAL; 774*4882a593Smuzhiyun+ 775*4882a593Smuzhiyun+ buf = getenv("WESTON_DRM_HEAD_MODE"); 776*4882a593Smuzhiyun+ if (buf) { 777*4882a593Smuzhiyun+ if (!strcmp(buf, "primary")) 778*4882a593Smuzhiyun+ head_mode = DRM_HEAD_MODE_PRIMARY; 779*4882a593Smuzhiyun+ else if (!strcmp(buf, "internal")) 780*4882a593Smuzhiyun+ head_mode = DRM_HEAD_MODE_INTERNAL; 781*4882a593Smuzhiyun+ else if (!strcmp(buf, "external")) 782*4882a593Smuzhiyun+ head_mode = DRM_HEAD_MODE_EXTERNAL; 783*4882a593Smuzhiyun+ else if (!strcmp(buf, "external-dual")) 784*4882a593Smuzhiyun+ head_mode = DRM_HEAD_MODE_EXTERNAL_DUAL; 785*4882a593Smuzhiyun+ } 786*4882a593Smuzhiyun+ 787*4882a593Smuzhiyun+ b->head_matches = drm_head_matches[head_mode]; 788*4882a593Smuzhiyun+ 789*4882a593Smuzhiyun+ buf = getenv("WESTON_DRM_RESIZE_FREEZE_MS"); 790*4882a593Smuzhiyun+ if (buf) 791*4882a593Smuzhiyun+ b->resize_freeze_ms = atoi(buf); 792*4882a593Smuzhiyun+ else 793*4882a593Smuzhiyun+ b->resize_freeze_ms = DRM_RESIZE_FREEZE_MS; 794*4882a593Smuzhiyun+ 795*4882a593Smuzhiyun device = zalloc(sizeof *device); 796*4882a593Smuzhiyun if (device == NULL) 797*4882a593Smuzhiyun return NULL; 798*4882a593Smuzhiyun@@ -3241,7 +3526,7 @@ drm_backend_create(struct weston_compositor *compositor, 799*4882a593Smuzhiyun } 800*4882a593Smuzhiyun 801*4882a593Smuzhiyun wl_list_init(&b->drm->writeback_connector_list); 802*4882a593Smuzhiyun- if (drm_backend_discover_connectors(b->drm, drm_device, res) < 0) { 803*4882a593Smuzhiyun+ if (drm_backend_update_connectors(b->drm, drm_device) < 0) { 804*4882a593Smuzhiyun weston_log("Failed to create heads for %s\n", b->drm->drm.filename); 805*4882a593Smuzhiyun goto err_udev_input; 806*4882a593Smuzhiyun } 807*4882a593Smuzhiyun@@ -3280,6 +3565,10 @@ drm_backend_create(struct weston_compositor *compositor, 808*4882a593Smuzhiyun 809*4882a593Smuzhiyun udev_device_unref(drm_device); 810*4882a593Smuzhiyun 811*4882a593Smuzhiyun+ b->output_create_listener.notify = output_create_notify; 812*4882a593Smuzhiyun+ wl_signal_add(&b->compositor->output_created_signal, 813*4882a593Smuzhiyun+ &b->output_create_listener); 814*4882a593Smuzhiyun+ 815*4882a593Smuzhiyun weston_compositor_add_debug_binding(compositor, KEY_O, 816*4882a593Smuzhiyun planes_binding, b); 817*4882a593Smuzhiyun weston_compositor_add_debug_binding(compositor, KEY_C, 818*4882a593Smuzhiyun@@ -3339,6 +3628,9 @@ drm_backend_create(struct weston_compositor *compositor, 819*4882a593Smuzhiyun goto err_udev_monitor; 820*4882a593Smuzhiyun } 821*4882a593Smuzhiyun 822*4882a593Smuzhiyun+ b->hotplug_timer = 823*4882a593Smuzhiyun+ wl_event_loop_add_timer(loop, hotplug_timer_handler, b->drm); 824*4882a593Smuzhiyun+ 825*4882a593Smuzhiyun return b; 826*4882a593Smuzhiyun 827*4882a593Smuzhiyun err_udev_monitor: 828*4882a593Smuzhiyundiff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c 829*4882a593Smuzhiyunindex 735196b..c7dc2f8 100644 830*4882a593Smuzhiyun--- a/libweston/backend-drm/kms.c 831*4882a593Smuzhiyun+++ b/libweston/backend-drm/kms.c 832*4882a593Smuzhiyun@@ -683,6 +683,8 @@ drm_output_apply_state_legacy(struct drm_output_state *state) 833*4882a593Smuzhiyun 834*4882a593Smuzhiyun scanout_state = 835*4882a593Smuzhiyun drm_output_state_get_existing_plane(state, scanout_plane); 836*4882a593Smuzhiyun+ if (!scanout_state || !scanout_state->fb) 837*4882a593Smuzhiyun+ return 0; 838*4882a593Smuzhiyun 839*4882a593Smuzhiyun /* The legacy SetCrtc API doesn't allow us to do scaling, and the 840*4882a593Smuzhiyun * legacy PageFlip API doesn't allow us to do clipping either. */ 841*4882a593Smuzhiyun@@ -700,7 +702,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state) 842*4882a593Smuzhiyun assert(scanout_state->in_fence_fd == -1); 843*4882a593Smuzhiyun 844*4882a593Smuzhiyun mode = to_drm_mode(output->base.current_mode); 845*4882a593Smuzhiyun- if (device->state_invalid || 846*4882a593Smuzhiyun+ if (output->state_invalid || 847*4882a593Smuzhiyun !scanout_plane->state_cur->fb || 848*4882a593Smuzhiyun scanout_plane->state_cur->fb->strides[0] != 849*4882a593Smuzhiyun scanout_state->fb->strides[0]) { 850*4882a593Smuzhiyun@@ -714,6 +716,8 @@ drm_output_apply_state_legacy(struct drm_output_state *state) 851*4882a593Smuzhiyun weston_log("set mode failed: %s\n", strerror(errno)); 852*4882a593Smuzhiyun goto err; 853*4882a593Smuzhiyun } 854*4882a593Smuzhiyun+ 855*4882a593Smuzhiyun+ output->state_invalid = false; 856*4882a593Smuzhiyun } 857*4882a593Smuzhiyun 858*4882a593Smuzhiyun pinfo = scanout_state->fb->format; 859*4882a593Smuzhiyun@@ -964,6 +968,11 @@ drm_output_apply_state_atomic(struct drm_output_state *state, 860*4882a593Smuzhiyun *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; 861*4882a593Smuzhiyun } 862*4882a593Smuzhiyun 863*4882a593Smuzhiyun+ if (output->state_invalid) { 864*4882a593Smuzhiyun+ drm_debug(b, "\t\t\t[atomic] output state invalid, modeset OK\n"); 865*4882a593Smuzhiyun+ *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; 866*4882a593Smuzhiyun+ } 867*4882a593Smuzhiyun+ 868*4882a593Smuzhiyun if (state->dpms == WESTON_DPMS_ON) { 869*4882a593Smuzhiyun ret = drm_mode_ensure_blob(device, current_mode); 870*4882a593Smuzhiyun if (ret != 0) 871*4882a593Smuzhiyun@@ -1080,6 +1089,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state, 872*4882a593Smuzhiyun struct drm_output_state *output_state, *tmp; 873*4882a593Smuzhiyun struct drm_plane *plane; 874*4882a593Smuzhiyun drmModeAtomicReq *req = drmModeAtomicAlloc(); 875*4882a593Smuzhiyun+ struct timespec now; 876*4882a593Smuzhiyun uint32_t flags; 877*4882a593Smuzhiyun int ret = 0; 878*4882a593Smuzhiyun 879*4882a593Smuzhiyun@@ -1214,14 +1224,34 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state, 880*4882a593Smuzhiyun goto out; 881*4882a593Smuzhiyun } 882*4882a593Smuzhiyun 883*4882a593Smuzhiyun+ weston_compositor_read_presentation_clock(b->compositor, &now); 884*4882a593Smuzhiyun+ 885*4882a593Smuzhiyun wl_list_for_each_safe(output_state, tmp, &pending_state->output_list, 886*4882a593Smuzhiyun- link) 887*4882a593Smuzhiyun+ link) { 888*4882a593Smuzhiyun+ struct drm_output *output = output_state->output; 889*4882a593Smuzhiyun+ struct drm_plane *scanout_plane = output->scanout_plane; 890*4882a593Smuzhiyun+ struct drm_plane_state *scanout_state = 891*4882a593Smuzhiyun+ drm_output_state_get_existing_plane(output_state, 892*4882a593Smuzhiyun+ scanout_plane); 893*4882a593Smuzhiyun+ 894*4882a593Smuzhiyun+ /* Don't have a new state to apply */ 895*4882a593Smuzhiyun+ if (output_state->dpms == WESTON_DPMS_ON && 896*4882a593Smuzhiyun+ (!scanout_state || !scanout_state->fb)) 897*4882a593Smuzhiyun+ continue; 898*4882a593Smuzhiyun+ 899*4882a593Smuzhiyun drm_output_assign_state(output_state, mode); 900*4882a593Smuzhiyun+ output->state_invalid = false; 901*4882a593Smuzhiyun+ 902*4882a593Smuzhiyun+ /* Not gonna receive flip event when dpms off */ 903*4882a593Smuzhiyun+ if (output_state->dpms != WESTON_DPMS_ON) 904*4882a593Smuzhiyun+ drm_output_update_complete(output, 905*4882a593Smuzhiyun+ WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION, 906*4882a593Smuzhiyun+ now.tv_sec, 907*4882a593Smuzhiyun+ now.tv_nsec / 1000); 908*4882a593Smuzhiyun+ } 909*4882a593Smuzhiyun 910*4882a593Smuzhiyun device->state_invalid = false; 911*4882a593Smuzhiyun 912*4882a593Smuzhiyun- assert(wl_list_empty(&pending_state->output_list)); 913*4882a593Smuzhiyun- 914*4882a593Smuzhiyun out: 915*4882a593Smuzhiyun drmModeAtomicFree(req); 916*4882a593Smuzhiyun drm_pending_state_free(pending_state); 917*4882a593Smuzhiyun@@ -1321,8 +1351,6 @@ drm_pending_state_apply(struct drm_pending_state *pending_state) 918*4882a593Smuzhiyun 919*4882a593Smuzhiyun device->state_invalid = false; 920*4882a593Smuzhiyun 921*4882a593Smuzhiyun- assert(wl_list_empty(&pending_state->output_list)); 922*4882a593Smuzhiyun- 923*4882a593Smuzhiyun drm_pending_state_free(pending_state); 924*4882a593Smuzhiyun 925*4882a593Smuzhiyun return 0; 926*4882a593Smuzhiyun@@ -1374,8 +1402,6 @@ drm_pending_state_apply_sync(struct drm_pending_state *pending_state) 927*4882a593Smuzhiyun 928*4882a593Smuzhiyun device->state_invalid = false; 929*4882a593Smuzhiyun 930*4882a593Smuzhiyun- assert(wl_list_empty(&pending_state->output_list)); 931*4882a593Smuzhiyun- 932*4882a593Smuzhiyun drm_pending_state_free(pending_state); 933*4882a593Smuzhiyun 934*4882a593Smuzhiyun return 0; 935*4882a593Smuzhiyundiff --git a/libweston/compositor.c b/libweston/compositor.c 936*4882a593Smuzhiyunindex 9f8282b..2125f1a 100644 937*4882a593Smuzhiyun--- a/libweston/compositor.c 938*4882a593Smuzhiyun+++ b/libweston/compositor.c 939*4882a593Smuzhiyun@@ -160,6 +160,25 @@ weston_paint_node_destroy(struct weston_paint_node *pnode) 940*4882a593Smuzhiyun free(pnode); 941*4882a593Smuzhiyun } 942*4882a593Smuzhiyun 943*4882a593Smuzhiyun+static struct weston_layer * 944*4882a593Smuzhiyun+get_view_layer(struct weston_view *view); 945*4882a593Smuzhiyun+ 946*4882a593Smuzhiyun+static bool 947*4882a593Smuzhiyun+weston_compositor_is_static_layer(struct weston_layer *layer) 948*4882a593Smuzhiyun+{ 949*4882a593Smuzhiyun+ if (!layer) 950*4882a593Smuzhiyun+ return false; 951*4882a593Smuzhiyun+ 952*4882a593Smuzhiyun+ switch (layer->position) { 953*4882a593Smuzhiyun+ case WESTON_LAYER_POSITION_BACKGROUND: 954*4882a593Smuzhiyun+ case WESTON_LAYER_POSITION_UI: 955*4882a593Smuzhiyun+ case WESTON_LAYER_POSITION_FADE: 956*4882a593Smuzhiyun+ return true; 957*4882a593Smuzhiyun+ default: 958*4882a593Smuzhiyun+ return false; 959*4882a593Smuzhiyun+ } 960*4882a593Smuzhiyun+} 961*4882a593Smuzhiyun+ 962*4882a593Smuzhiyun /** Send wl_output events for mode and scale changes 963*4882a593Smuzhiyun * 964*4882a593Smuzhiyun * \param head Send on all resources bound to this head. 965*4882a593Smuzhiyun@@ -1386,6 +1405,22 @@ weston_view_assign_output(struct weston_view *ev) 966*4882a593Smuzhiyun uint32_t max, area, mask; 967*4882a593Smuzhiyun pixman_box32_t *e; 968*4882a593Smuzhiyun 969*4882a593Smuzhiyun+ /* The static views should bind to the specific output */ 970*4882a593Smuzhiyun+ if (weston_compositor_is_static_layer(get_view_layer(ev))) { 971*4882a593Smuzhiyun+ struct weston_view *view = ev; 972*4882a593Smuzhiyun+ 973*4882a593Smuzhiyun+ while (view && !(output = view->output)) 974*4882a593Smuzhiyun+ view = view->geometry.parent; 975*4882a593Smuzhiyun+ 976*4882a593Smuzhiyun+ if (output && !output->destroying) 977*4882a593Smuzhiyun+ ev->output_mask = 1u << output->id; 978*4882a593Smuzhiyun+ else 979*4882a593Smuzhiyun+ weston_view_set_output(ev, NULL); 980*4882a593Smuzhiyun+ 981*4882a593Smuzhiyun+ weston_surface_assign_output(ev->surface); 982*4882a593Smuzhiyun+ return; 983*4882a593Smuzhiyun+ } 984*4882a593Smuzhiyun+ 985*4882a593Smuzhiyun new_output = NULL; 986*4882a593Smuzhiyun max = 0; 987*4882a593Smuzhiyun mask = 0; 988*4882a593Smuzhiyun@@ -3301,6 +3336,7 @@ weston_output_repaint(struct weston_output *output) 989*4882a593Smuzhiyun if (output->dirty) 990*4882a593Smuzhiyun weston_output_update_matrix(output); 991*4882a593Smuzhiyun 992*4882a593Smuzhiyun+ output->repaint_needed = false; 993*4882a593Smuzhiyun r = output->repaint(output, &output_damage); 994*4882a593Smuzhiyun 995*4882a593Smuzhiyun /* Clear painted primary damage */ 996*4882a593Smuzhiyun@@ -3309,8 +3345,9 @@ weston_output_repaint(struct weston_output *output) 997*4882a593Smuzhiyun 998*4882a593Smuzhiyun pixman_region32_fini(&output_damage); 999*4882a593Smuzhiyun 1000*4882a593Smuzhiyun- output->repaint_needed = false; 1001*4882a593Smuzhiyun- if (r == 0) 1002*4882a593Smuzhiyun+ if (output->repaint_needed) 1003*4882a593Smuzhiyun+ output->repaint_status = REPAINT_SCHEDULED; 1004*4882a593Smuzhiyun+ else if (r == 0) 1005*4882a593Smuzhiyun output->repaint_status = REPAINT_AWAITING_COMPLETION; 1006*4882a593Smuzhiyun 1007*4882a593Smuzhiyun weston_compositor_repick(ec); 1008*4882a593Smuzhiyun@@ -6911,6 +6948,7 @@ weston_compositor_remove_output(struct weston_output *output) 1009*4882a593Smuzhiyun * Use view_list in case the output did not go through repaint 1010*4882a593Smuzhiyun * after a view came on it, lacking a paint node. Just to be sure. 1011*4882a593Smuzhiyun */ 1012*4882a593Smuzhiyun+ weston_compositor_build_view_list(compositor, NULL); 1013*4882a593Smuzhiyun wl_list_for_each(view, &compositor->view_list, link) { 1014*4882a593Smuzhiyun if (view->output_mask & (1u << output->id)) 1015*4882a593Smuzhiyun weston_view_assign_output(view); 1016*4882a593Smuzhiyun-- 1017*4882a593Smuzhiyun2.20.1 1018*4882a593Smuzhiyun 1019