Allow Dual Screen Configurations for intel IGPs

improve xrandr_facts.py to match drm and xrandr outputs

TODO: use drm.edid_firmware kernel boot parameter to load EDID files
  on startup
This commit is contained in:
Alexander Grothe 2019-02-22 00:12:02 +01:00
parent c0dc185952
commit 08ed05594e
5 changed files with 966 additions and 593 deletions

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,26 @@
#+LATEX: \defaultfontfeatures{Ligatures=TeX} #+LATEX: \defaultfontfeatures{Ligatures=TeX}
#+LATEX_HEADER: \usepackage{parskip} #+LATEX_HEADER: \usepackage{parskip}
# #+LATEX_HEADER_EXTRA: # #+LATEX_HEADER_EXTRA:
#+BEGIN_SRC latex
\newcommand*\justify{%
\fontdimen2\font=0.4em% interword space
\fontdimen3\font=0.2em% interword stretch
\fontdimen4\font=0.1em% interword shrink
\fontdimen7\font=0.1em% extra space
\hyphenchar\font=`\-% allowing hyphenation
}
\renewcommand{\texttt}[1]{%
\begingroup
\ttfamily
\begingroup\lccode`~=`/\lowercase{\endgroup\def~}{/\discretionary{}{}{}}%
\begingroup\lccode`~=`[\lowercase{\endgroup\def~}{[\discretionary{}{}{}}%
\begingroup\lccode`~=`.\lowercase{\endgroup\def~}{.\discretionary{}{}{}}%
\catcode`/=\active\catcode`[=\active\catcode`.=\active
\justify\scantokens{#1\noexpand}%
\endgroup
}
#+END_SRC
#+EXCLUDE_TAGS: noexport #+EXCLUDE_TAGS: noexport
:END: :END:
@ -1832,7 +1852,7 @@ ctl.!default {
The X-Server is started by using the two systemd units ~xlogin@.service~ and ~x@.service~ provided by the package *xlogin*. The former is enabled (and started) for the vdr user - which results (using the default settings for the user *vdr* with the uid *666*) in the activation of ~xlogin@vdr.service~ when reaching the graphical.target. To simplify starting and stopping the X-server and the desktop session a ~yavdr-xorg.service~ is provided by the package ~yavdr-xorg~, which depends on the two units mentioned before. The X-Server is started by using the two systemd units ~xlogin@.service~ and ~x@.service~ provided by the package *xlogin*. The former is enabled (and started) for the vdr user - which results (using the default settings for the user *vdr* with the uid *666*) in the activation of ~xlogin@vdr.service~ when reaching the graphical.target. To simplify starting and stopping the X-server and the desktop session a ~yavdr-xorg.service~ is provided by the package ~yavdr-xorg~, which depends on the two units mentioned before.
~x@vt7.service~ is started automatically as a dependency of ~xlogin@vdr.service~ and starts the X-server. ~xlogin@vdr.service~ also starts a systemd user session using ~user@666.service~. ~x@vt7.service~ is started automatically as a dependency of ~xlogin@vdr.service~ and starts the X-server. ~xlogin@vdr.service~ also starts a systemd user session using ~user@666.service~.
In order to use the keyboard layout configured during installation for the X-Server the script ~write-x11-keyboard-config~ reads the keyboard configuration from ~/etc/default/keyboard~ when starting ~x@.service~ and writes the file ~/etc/X11/xorg.conf.d/00-keyboard.conf~ (because systemd for Ubuntu (and Debian) has been patched not to create ~/etc/X11/xorg.conf.d/00-keyboard.conf~ according to the ~localectl~ settings). In order to use the keyboard layout configured during installation for the X-Server we are using a script ~write-x11-keyboard-config,~ which reads the keyboard configuration from ~/etc/default/keyboard~ when starting ~x@.service~ and writes the file ~/etc/X11/xorg.conf.d/00-keyboard.conf~ (because systemd for Ubuntu (and Debian) has been patched not to automatically create the configuration file ~/etc/X11/xorg.conf.d/00-keyboard.conf~ according to the ~localectl~ settings).
To prevent stopping the X-server when vdr is running, additional dependencies are set up - see the drop-in rules created in ~/etc/systemd/system/vdr.service.d/~. To prevent stopping the X-server when vdr is running, additional dependencies are set up - see the drop-in rules created in ~/etc/systemd/system/vdr.service.d/~.
@ -2336,6 +2356,12 @@ preferred_refreshrates:
- '-w alsa-driver-broken' - '-w alsa-driver-broken'
# - '-a pulse' # do we need this with our existing asound.conf? # - '-a pulse' # do we need this with our existing asound.conf?
- name: vdr-config | use vaapi for softhddevice if we got an intel IGP
lineinfile:
path: /etc/vdr/conf.avail/softhddevice.conf
line: '-v va-pi'
state: present if intel_detected else absent
- name: add a login shell for the user vdr - name: add a login shell for the user vdr
user: user:
name: '{{ vdr.user }}' name: '{{ vdr.user }}'
@ -2704,21 +2730,41 @@ EndSection
***** intel graphics xorg.conf snippet ***** intel graphics xorg.conf snippet
#+BEGIN_SRC jinja2 :tangle roles/yavdr-xorg/templates/20-intel.conf.j2 #+BEGIN_SRC jinja2 :tangle roles/yavdr-xorg/templates/20-intel.conf.j2
{{ ansible_managed | comment }} {{ ansible_managed | comment }}
{% set primary_output = xorg.primary.connector|replace("-", "") %}
{% set output = xorg.primary.connector|replace("-", "") %} {% if xorg.secondary is defined %}
{% set secondary_output = xorg.secondary.connector|replace("-", "") %}
{% endif %}
Section "Device" Section "Device"
Identifier "Device0" Identifier "Device0"
Driver "intel" Driver "intel"
Option "TearFree" "true" Option "TearFree" "true"
{% if xorg.secondary is defined %}
Option "UseEDID" "true" Option "ZaphodHeads" "{{ primary_output }}"
Option "CustomEDID" "{{ output }}:{{ xorg.primary.edid }}" Screen 0
{% endif %}
EndSection EndSection
{% if xorg.secondary is defined %}
Section "Device"
Identifier "Device1"
Driver "intel"
Option "TearFree" "true"
Option "ZaphodHeads" "{{ secondary_output }}"
Screen 1
EndSection
Section "ServerLayout"
Identifier "Layout0"
Screen 0 "Screen0" 0 0
Screen 1 "Screen1" RightOf "Screen0"
EndSection
{% endif %}
Section "Screen" Section "Screen"
Identifier "Screen0" Identifier "Screen0"
Device "Device0" Device "Device0"
Monitor "{{ output }}" Monitor "{{ primary_output }}"
DefaultDepth 24 DefaultDepth 24
SubSection "Display" SubSection "Display"
Depth 24 Depth 24
@ -2729,8 +2775,26 @@ Section "Screen"
{% endif %} {% endif %}
EndSubSection EndSubSection
EndSection EndSection
{% if xorg.secondary is defined %}
Section "Screen"
Identifier "Screen1"
Device "Device1"
Monitor "{{ secondary_output }}"
DefaultDepth 24
SubSection "Display"
Depth 24
{% if xorg.secondary.mode %}
Modes "{{ xorg.secondary.mode }}"
{% else %}
Modes "1920x1080_50" "1920x1080_60" "1920x1080_24"
{% endif %}
EndSubSection
EndSection
{% endif %}
Section "Monitor" Section "Monitor"
Identifier "{{ output }}" Identifier "{{ primary_output }}"
{% if xorg.primary.modelines %} {% if xorg.primary.modelines %}
{% for modeline in xorg.primary.modelines %} {% for modeline in xorg.primary.modelines %}
{{ modeline }} {{ modeline }}
@ -2742,8 +2806,23 @@ Section "Monitor"
{% endif %} {% endif %}
EndSection EndSection
{% if xorg.secondary is defined %}
Section "Monitor"
Identifier "{{ secondary_output }}"
{% if xorg.secondary.modelines %}
{% for modeline in xorg.secondary.modelines %}
{{ modeline }}
{% endfor %}
{% else %}
Modeline "1920x1080_24" 74.230 1920 2560 2604 2752 1080 1084 1089 1125 +hsync +vsync
Modeline "1920x1080_50" 148.500 1920 2448 2492 2640 1080 1084 1089 1125 +hsync +vsync
Modeline "1920x1080_60" 148.500 1920 2008 2056 2200 1080 1084 1089 1125 +hsync +vsync
{% endif %}
EndSection
{% endif %}
{% for connector, data in xrandr["Screen 0:"].iteritems() %} {% for connector, data in xrandr["Screen 0:"].iteritems() %}
{% if not data.is_connected or connector != xorg.primary.connector %} {% if not data.is_connected or connector != xorg.primary.connector or (xorg.secondary is defined and connector != xorg.secondary.connector) %}
Section "Monitor" Section "Monitor"
Identifier "{{ connector|replace("-","") }}" Identifier "{{ connector|replace("-","") }}"
Option "Ignore" "true" Option "Ignore" "true"

View File

@ -255,33 +255,39 @@ def collect_nvidia_data():
raise ValueError raise ValueError
Connector = namedtuple('Connector', "name xrandr_edid") def find_drm_connectors(connections):
def find_drm_connectors(primary):
""" """
takes a namedtuple Connector as the only argument. returns a dict with the following schema (secondary may be empty):
returns a dict with the following schema:
{ {
'primary': { 'primary': {
'edid': 'edid.HDMI-1.bin', 'edid': 'edid.HDMI-1.bin',
'drm_connector': 'HDMI-A-1', 'drm_connector': 'HDMI-A-1',
'xrandr_connector': 'HDMI-1', 'xrandr_connector': 'HDMI-1',
}, },
'secondary': {
'edid': 'edid.eDP-1.bin',
'drm_connector': 'eDP-1',
'xrandr_connector': 'eDP-1',
}
'ignored_outputs': ['HDMI-A-2', 'DP-1'] 'ignored_outputs': ['HDMI-A-2', 'DP-1']
} }
""" """
STATUS_GLOB = '/sys/class/drm/card0*/status' STATUS_GLOB = '/sys/class/drm/card0*/status'
CONNECTOR_RE = re.compile('card0-(?P<connector>[^/]+)/status') CONNECTOR_RE = re.compile('card0-(?P<connector>[^/]+)/status')
def read_edid_bytes(edid_file):
edid_bytes = b''
try: try:
with open(primary.xrandr_edid, 'rb') as f: with open(edid_file, 'rb') as f:
xrandr_edid_bytes = f.read() edid_bytes = f.read()
except IOError: except IOError:
xrandr_edid_bytes = b'' pass
return edid_bytes
drm = {'primary': {}, 'ignored_outputs': []} xrandr_edid_bytes = read_edid_bytes(connections.get('primary', {}).get('edid', ""))
secondary_xrandr_edid_bytes = read_edid_bytes(connections.get('secondary', {}).get('edid', ''))
drm = {'primary': {}, 'secondary': {}, 'ignored_outputs': []}
for status_p in glob(STATUS_GLOB): for status_p in glob(STATUS_GLOB):
match = re.search(CONNECTOR_RE, status_p) match = re.search(CONNECTOR_RE, status_p)
if match: if match:
@ -295,19 +301,22 @@ def find_drm_connectors(primary):
except IOError: except IOError:
continue continue
if connected and xrandr_edid_bytes: if connected:
drm_edid = os.path.join(os.path.dirname(status_p), 'edid') edid = read_edid_bytes(os.path.join(
try: os.path.dirname(status_p), 'edid'))
with open(drm_edid, 'rb') as f: if edid:
is_primary = f.read() == xrandr_edid_bytes if edid == xrandr_edid_bytes:
except IOError:
continue
else:
if is_primary:
drm['primary'] = { drm['primary'] = {
'edid': os.path.basename(primary.xrandr_edid), 'edid': os.path.basename(connections['primary'].get('edid', "")),
'drm_connector': drm_connector, 'drm_connector': drm_connector,
'xrandr_connector': primary.name, 'xrandr_connector': connections['primary'].get('connector',''),
}
continue
if secondary_xrandr_edid_bytes:
drm['secondary'] = {
'edid': os.path.basename(connections.get('secondary').get('edid', '')),
'drm_connector': drm_connector,
'xrandr_connector': connections['secondary'].get('connector',''),
} }
continue continue
drm['ignored_outputs'].append(drm_connector) drm['ignored_outputs'].append(drm_connector)
@ -350,22 +359,24 @@ def output_data(data, write_edids=True):
result[name]['bus_id'] = bus_id result[name]['bus_id'] = bus_id
connector_0, resolution_0, refreshrate_0 = max(modes, key=sort_mode)[:3] connector_0, resolution_0, refreshrate_0 = max(modes, key=sort_mode)[:3]
vendor_0, model_0, modelines_0 = parse_edid_data('/etc/X11/edid.{}.bin'.format(connector_0)) connector_0_edid = '/etc/X11/edid.{}.bin'.format(connector_0)
vendor_0, model_0, modelines_0 = parse_edid_data(connector_0_edid)
create_entry(result, 'primary', connector_0, resolution_0, create_entry(result, 'primary', connector_0, resolution_0,
refreshrate_0, vendor_0, model_0, modelines_0) refreshrate_0, vendor_0, model_0, modelines_0)
if write_edids:
drm = find_drm_connectors(Connector(connector_0,
'/etc/X11/edid.{}.bin'.format(connector_0)))
# check if additional monitors exist # check if additional monitors exist
other_modes = [mode for mode in modes if mode[0] != connector_0] other_modes = [mode for mode in modes if mode[0] != connector_0]
if other_modes: if other_modes:
connector_1, resolution_1, refreshrate_1 = max(other_modes, key=sort_mode)[:3] connector_1, resolution_1, refreshrate_1 = max(other_modes, key=sort_mode)[:3]
vendor_1, model_1, modelines_1 = parse_edid_data('/etc/X11/edid.{}.bin'.format(connector_1)) connector_1_edid = '/etc/X11/edid.{}.bin'.format(connector_1)
vendor_1, model_1, modelines_1 = parse_edid_data(connector_1_edid)
create_entry(result, 'secondary', connector_1, resolution_1, create_entry(result, 'secondary', connector_1, resolution_1,
refreshrate_1, vendor_1, model_1, modelines_1) refreshrate_1, vendor_1, model_1, modelines_1)
if write_edids:
drm = find_drm_connectors(result)
module.exit_json(changed=True if write_edids else False, module.exit_json(changed=True if write_edids else False,
ansible_facts={'xrandr': data, 'xorg': result, 'drm': drm}) ansible_facts={'xrandr': data, 'xorg': result, 'drm': drm})

View File

@ -44,6 +44,12 @@
- '-w alsa-driver-broken' - '-w alsa-driver-broken'
# - '-a pulse' # do we need this with our existing asound.conf? # - '-a pulse' # do we need this with our existing asound.conf?
- name: vdr-config | use vaapi for softhddevice if we got an intel IGP
lineinfile:
path: /etc/vdr/conf.avail/softhddevice.conf
line: '-v va-pi'
state: present if intel_detected else absent
- name: add a login shell for the user vdr - name: add a login shell for the user vdr
user: user:
name: '{{ vdr.user }}' name: '{{ vdr.user }}'

View File

@ -1,19 +1,39 @@
{{ ansible_managed | comment }} {{ ansible_managed | comment }}
{% set primary_output = xorg.primary.connector|replace("-", "") %}
{% set output = xorg.primary.connector|replace("-", "") %} {% if xorg.secondary is defined %}
{% set secondary_output = xorg.secondary.connector|replace("-", "") %}
{% endif %}
Section "Device" Section "Device"
Identifier "Device0" Identifier "Device0"
Driver "intel" Driver "intel"
Option "TearFree" "true" Option "TearFree" "true"
{% if xorg.secondary is defined %}
Option "UseEDID" "true" Option "ZaphodHeads" "{{ primary_output }}"
Option "CustomEDID" "{{ output }}:{{ xorg.primary.edid }}" Screen 0
{% endif %}
EndSection EndSection
{% if xorg.secondary is defined %}
Section "Device"
Identifier "Device1"
Driver "intel"
Option "TearFree" "true"
Option "ZaphodHeads" "{{ secondary_output }}"
Screen 1
EndSection
Section "ServerLayout"
Identifier "Layout0"
Screen 0 "Screen0" 0 0
Screen 1 "Screen1" RightOf "Screen0"
EndSection
{% endif %}
Section "Screen" Section "Screen"
Identifier "Screen0" Identifier "Screen0"
Device "Device0" Device "Device0"
Monitor "{{ output }}" Monitor "{{ primary_output }}"
DefaultDepth 24 DefaultDepth 24
SubSection "Display" SubSection "Display"
Depth 24 Depth 24
@ -24,8 +44,26 @@ Section "Screen"
{% endif %} {% endif %}
EndSubSection EndSubSection
EndSection EndSection
{% if xorg.secondary is defined %}
Section "Screen"
Identifier "Screen1"
Device "Device1"
Monitor "{{ secondary_output }}"
DefaultDepth 24
SubSection "Display"
Depth 24
{% if xorg.secondary.mode %}
Modes "{{ xorg.secondary.mode }}"
{% else %}
Modes "1920x1080_50" "1920x1080_60" "1920x1080_24"
{% endif %}
EndSubSection
EndSection
{% endif %}
Section "Monitor" Section "Monitor"
Identifier "{{ output }}" Identifier "{{ primary_output }}"
{% if xorg.primary.modelines %} {% if xorg.primary.modelines %}
{% for modeline in xorg.primary.modelines %} {% for modeline in xorg.primary.modelines %}
{{ modeline }} {{ modeline }}
@ -37,8 +75,23 @@ Section "Monitor"
{% endif %} {% endif %}
EndSection EndSection
{% if xorg.secondary is defined %}
Section "Monitor"
Identifier "{{ secondary_output }}"
{% if xorg.secondary.modelines %}
{% for modeline in xorg.secondary.modelines %}
{{ modeline }}
{% endfor %}
{% else %}
Modeline "1920x1080_24" 74.230 1920 2560 2604 2752 1080 1084 1089 1125 +hsync +vsync
Modeline "1920x1080_50" 148.500 1920 2448 2492 2640 1080 1084 1089 1125 +hsync +vsync
Modeline "1920x1080_60" 148.500 1920 2008 2056 2200 1080 1084 1089 1125 +hsync +vsync
{% endif %}
EndSection
{% endif %}
{% for connector, data in xrandr["Screen 0:"].iteritems() %} {% for connector, data in xrandr["Screen 0:"].iteritems() %}
{% if not data.is_connected or connector != xorg.primary.connector %} {% if not data.is_connected or connector != xorg.primary.connector or (xorg.secondary is defined and connector != xorg.secondary.connector) %}
Section "Monitor" Section "Monitor"
Identifier "{{ connector|replace("-","") }}" Identifier "{{ connector|replace("-","") }}"
Option "Ignore" "true" Option "Ignore" "true"