#!/usr/bin/env python3
import os
import subprocess
import sys
import tempfile
cc = os.getenv("CC", "cc")
pkg_config = os.getenv("PKG_CONFIG", "pkg-config")
gofmt = os.getenv("GOFMT", "gofmt")
version = subprocess.check_output([pkg_config, "libdrm", "--modversion"]).decode().strip()
cflags = subprocess.check_output([pkg_config, "libdrm", "--cflags-only-I"]).decode().strip().split()
found = False
for flag in cflags:
if not flag.startswith("-I"):
raise Exception("Expected an include dir for libdrm")
libdrm_include = flag[2:]
fourcc_include = libdrm_include + "/drm_fourcc.h"
if os.path.exists(fourcc_include):
found = True
break
if not found:
raise Exception("Failed to find drm_fourcc.h in libdrm -I cflags")
ident_list = []
with open(fourcc_include) as input_file:
for l in input_file.readlines():
parts = l.split()
if len(parts) < 3 or parts[0] != "#define":
continue
ident = parts[1]
if not ident.startswith("DRM_FORMAT_") and not ident.startswith("I915_FORMAT_"):
continue
if "(" in ident:
# Some complicated formats use a macro with parameters
continue
ident_list.append(ident)
idents = {}
with tempfile.TemporaryDirectory() as work_dir:
c_file_name = work_dir + "/main.c"
exe_file_name = work_dir + "/main"
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 "' + fourcc_include + '"\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, l) in enumerate(output.splitlines()):
idents[ident_list[i]] = l
types = ["Format", "ModifierVendor", "Modifier"]
words = ["none", "invalid", "linear"]
initialisms = ["AMD", "NVIDIA", "ARM"]
def to_camel_case(s):
parts = s.split("_")
for (i, part) in enumerate(parts):
if not part in initialisms:
parts[i] = part.lower().capitalize()
return "".join(parts)
consts = {}
for (ident, val) in idents.items():
if "_MOD_" in ident:
t = "Modifier"
if ident.startswith("DRM_FORMAT_MOD_"):
ident = ident[len("DRM_FORMAT_MOD_"):]
if ident.startswith("VENDOR_"):
t = "ModifierVendor"
ident = ident[len("VENDOR_"):]
if ident.startswith("ARM_TYPE_"):
continue
else:
parts = ident.split("_FORMAT_MOD_")
assert(len(parts) == 2)
ident = parts[0] + "_" + parts[1]
if ident in ["NONE"]:
continue
elif ident.startswith("DRM_FORMAT_"):
t = "Format"
ident = ident[len("DRM_FORMAT_"):]
if ident in ["BIG_ENDIAN", "RESERVED"]:
continue
else:
assert(False)
name = ident
if ident.lower() in words:
name = ident.lower()
elif t == "ModifierVendor":
name = to_camel_case(ident)
if t == "ModifierVendor" or ident.lower() in words:
ident = to_camel_case(ident)
if t not in consts:
consts[t] = []
consts[t].append({"name": name, "go_ident": t + ident, "value": val, "type": t})
# Some constants are aliases. Detect and remove these.
for t, l in consts.items():
seen = set()
out = []
for cst in l:
if cst["value"] in seen:
continue
seen.add(cst["value"])
out.append(cst)
consts[t] = out
with open("fourcc_generated.go", "w+") as go_file:
go_file.write('// Code generated by fourcc.py - DO NOT EDIT\n')
go_file.write('// libdrm ' + version + '\n')
go_file.write('\n')
go_file.write('package drm\n')
for t in types:
go_file.write('\n')
go_file.write('const (\n')
for cst in consts[t]:
go_file.write('\t' + cst["go_ident"] + ' ' + cst["type"] + ' = ' + cst["value"] + '\n')
go_file.write(')\n')
go_file.write('\n')
go_file.write('func (v ' + t + ') str() string {\n')
go_file.write('\tswitch v {\n')
for cst in consts[t]:
go_file.write('\tcase ' + cst["go_ident"] + ':\n')
go_file.write('\t\treturn "' + cst["name"] + '"\n')
go_file.write('\tdefault:\n')
go_file.write('\t\treturn ""\n')
go_file.write('\t}\n')
go_file.write('}\n')
subprocess.check_call([gofmt, "-w", "fourcc_generated.go"])