1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
#!/usr/bin/env python3
# This script synchronizes wayland.xml's wl_shm.format enum with drm_fourcc.h.
# Invoke it to update wayland.xml, then manually check the changes applied.
#
# Requires Python 3, python-lxml, a C compiler and pkg-config.
import os
import subprocess
import sys
import tempfile
# We need lxml instead of the standard library because we want
# Element.sourceline
from lxml import etree as ElementTree
proto_dir = os.path.dirname(os.path.realpath(__file__))
wayland_proto = proto_dir + "/wayland.xml"
cc = os.getenv("CC", "cc")
pkg_config = os.getenv("PKG_CONFIG", "pkg-config")
# Find drm_fourcc.h
version = subprocess.check_output([pkg_config, "libdrm",
"--modversion"]).decode().strip()
cflags = subprocess.check_output([pkg_config, "libdrm",
"--cflags-only-I"]).decode().strip().split()
libdrm_include = None
for include_flag in cflags:
if not include_flag.startswith("-I"):
raise Exception("Expected one include dir for libdrm")
include_dir = include_flag[2:]
if include_dir.endswith("/libdrm"):
libdrm_include = include_dir
fourcc_include = libdrm_include + "/drm_fourcc.h"
if libdrm_include == None:
raise Exception("Failed to find libdrm include dir")
print("Using libdrm " + version, file=sys.stderr)
def drm_format_to_wl(ident):
return ident.replace("DRM_FORMAT_", "").lower()
# Collect DRM format constant names
ident_list = []
descriptions = {}
prev_comment = None
with open(fourcc_include) as input_file:
for l in input_file.readlines():
l = l.strip()
# Collect comments right before format definitions
if l.startswith("/*") and l.endswith("*/"):
prev_comment = l[2:-2]
continue
desc = prev_comment
prev_comment = None
# Recognize format definitions
parts = l.split()
if len(parts) < 3 or parts[0] != "#define":
continue
ident = parts[1]
if not ident.startswith("DRM_FORMAT_") or ident.startswith(
"DRM_FORMAT_MOD_"):
continue
ident_list.append(ident)
# Prefer in-line comments
if l.endswith("*/"):
desc = l[l.rfind("/*") + 2:-2]
if desc != None:
descriptions[drm_format_to_wl(ident)] = desc.strip()
# Collect DRM format values
idents = {}
with tempfile.TemporaryDirectory() as work_dir:
c_file_name = work_dir + "/print-formats.c"
exe_file_name = work_dir + "/print-formats"
with open(c_file_name, "w+") as c_file:
c_file.write('#include <inttypes.h>\n')
c_file.write('#include <stdint.h>\n')
c_file.write('#include <stdio.h>\n')
c_file.write('#include <drm_fourcc.h>\n')
c_file.write('\n')
c_file.write('int main(void) {\n')
for ident in ident_list:
c_file.write('printf("0x%" PRIX64 "\\n", (uint64_t)' + ident + ');\n')
c_file.write('}\n')
subprocess.check_call([cc, "-Wall", "-Wextra", "-o", exe_file_name,
c_file_name] + cflags)
output = subprocess.check_output([exe_file_name]).decode().strip()
for i, val in enumerate(output.splitlines()):
idents[ident_list[i]] = val
# We don't need those
del idents["DRM_FORMAT_BIG_ENDIAN"]
del idents["DRM_FORMAT_INVALID"]
del idents["DRM_FORMAT_RESERVED"]
# Convert from DRM constants to Wayland wl_shm.format entries
formats = {}
for ident, val in idents.items():
formats[drm_format_to_wl(ident)] = val.lower()
# Special case for ARGB8888 and XRGB8888
formats["argb8888"] = "0"
formats["xrgb8888"] = "1"
print("Loaded {} formats from drm_fourcc.h".format(len(formats)), file=sys.stderr)
tree = ElementTree.parse("wayland.xml")
root = tree.getroot()
wl_shm_format = root.find("./interface[@name='wl_shm']/enum[@name='format']")
if wl_shm_format == None:
raise Exception("wl_shm.format not found in wayland.xml")
# Remove formats we already know about
last_line = None
for node in wl_shm_format:
if node.tag != "entry":
continue
fmt = node.attrib["name"]
val = node.attrib["value"]
if fmt not in formats:
raise Exception("Format present in wl_shm.formats but not in "
"drm_fourcc.h: " + fmt)
if val != formats[fmt]:
raise Exception("Format value in wl_shm.formats ({}) differs "
"from value in drm_fourcc.h ({}) for format {}"
.format(val, formats[fmt], fmt))
del formats[fmt]
last_line = node.sourceline
if last_line == None:
raise Exception("Expected at least one existing wl_shm.format entry")
print("Adding {} formats to wayland.xml...".format(len(formats)), file=sys.stderr)
# Append new formats
new_wayland_proto = wayland_proto + ".new"
with open(new_wayland_proto, "w+") as output_file, \
open(wayland_proto) as input_file:
for i, l in enumerate(input_file.readlines()):
output_file.write(l)
if i + 1 == last_line:
for fmt, val in formats.items():
output_file.write(' <entry name="{}" value="{}"'
.format(fmt, val))
if fmt in descriptions:
output_file.write(' summary="{}"'.format(descriptions[fmt]))
output_file.write('/>\n')
os.rename(new_wayland_proto, wayland_proto)
|