| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- #!/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)
|