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