X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=scripts%2Fextgen.py;h=c8f87c3bf79278bb98e5e1342912f66570752cab;hb=e413e1d93464ffe7e7ef2b6ea2f28da3e6400166;hp=3cd2f5728f3b3d2019f17a0c9171eb230b85c454;hpb=16ab664fe93bffba059ea53deccbfed0305f7440;p=libs%2Fgl.git diff --git a/scripts/extgen.py b/scripts/extgen.py index 3cd2f572..c8f87c3b 100755 --- a/scripts/extgen.py +++ b/scripts/extgen.py @@ -4,68 +4,102 @@ import sys import os import xml.dom import xml.dom.minidom +import itertools + +### Command line processing ### if len(sys.argv)<2: print """Usage: - extgen.py [] [ ...]" + extgen.py [] [ ...] + extgen.py [] -Reads gl.spec and generates files to use . Any promoted functions +Reads gl.xml and generates files to use . Any promoted functions are exposed with their promoted names. If extensions are given, -any promoted functions from those are pulled in as well. can be -given to override the version where was promoted to core.""" +any promoted functions from those are pulled in as well. can +be given to override the version where was promoted to core. + +In the second form, the parameters are read from . If is +absent, the extension's lowercased name is used. Anything after the last dot +in is removed and replaced with cpp and h.""" sys.exit(0) -ext = sys.argv[1] +target_ext = sys.argv[1] out_base = None -if ext.endswith(".glext"): - fn = ext - ext = None - ver = None +if target_ext.endswith(".glext"): + fn = target_ext + target_ext = None + core_version = None secondary = [] for line in open(fn): parts = line.split() if parts[0]=="extension": - ext = parts[1] + target_ext = parts[1] elif parts[0]=="core_version": - ver = parts[1] + core_version = parts[1] elif parts[0]=="secondary": secondary.append(parts[1]) if len(sys.argv)>=3: out_base = os.path.splitext(sys.argv[2])[0] else: secondary = sys.argv[2:] - ver = None + core_version = None if secondary and secondary[0][0].isdigit(): - ver = secondary.pop(0) + core_version = secondary.pop(0) + +ext_type = target_ext.split('_')[0] +backport_ext = None -exttype = ext.split('_')[0] -bp_ext = None +if core_version: + core_version = map(int, core_version.split('.')) if not out_base: - out_base = ext.lower() + out_base = target_ext.lower() -class Function: - def __init__(self, name): +### XML file parsing ### + +class Thing: + FUNCTION = 1 + ENUM = 2 + + def __init__(self, name, kind): self.name = name - self.typedef = None + self.kind = kind self.version = None - self.category = None - self.vectorequiv = None + self.extension = None self.aliases = [] - self.extfunc = None + self.source = None + +class Function(Thing): + def __init__(self, name): + Thing.__init__(self, name, Thing.FUNCTION) + self.return_type = "void" + self.params = [] + self.typedef = None -funcs = {} -cur_func = None +class Enum(Thing): + def __init__(self, name): + Thing.__init__(self, name, Thing.ENUM) + self.value = 0 + +things = {} def get_nested_elements(elem, path): + childElements = [c for c in elem.childNodes if c.nodeType==xml.dom.Node.ELEMENT_NODE] if '/' in path: head, tail = path.split('/', 1) result = [] - for e in elem.getElementsByTagName(head): - result += get_nested_elements(e, tail) + for c in childElements: + if c.tagName==head: + result += get_nested_elements(c, tail) return result else: - return elem.getElementsByTagName(path) + return [c for c in childElements if c.tagName==path] + +def get_first_child(elem, tag): + for c in elem.childNodes: + if c.nodeType==xml.dom.Node.ELEMENT_NODE and c.tagName==tag: + return c + return None def get_text_contents(node): result = "" @@ -76,99 +110,160 @@ def get_text_contents(node): result += get_text_contents(c) return result +def parse_command(cmd): + proto = get_first_child(cmd, "proto") + name = get_text_contents(get_first_child(proto, "name")) + func = things.get(name) + if not func: + func = Function(name) + things[name] = func + + aliases = get_nested_elements(cmd, "alias") + func.aliases = [a.getAttribute("name") for a in aliases] + + ptype = get_first_child(proto, "ptype") + if ptype: + func.return_type = get_text_contents(ptype) + else: + for c in proto.childNodes: + if c.nodeType==xml.dom.Node.TEXT_NODE and c.data.strip(): + func.return_type = c.data.strip() + break + + params = get_nested_elements(cmd, "param") + func.params = map(get_text_contents, params) + +def parse_enum(en): + name = en.getAttribute("name") + enum = things.get(name) + if not enum: + enum = Enum(name) + things[name] = enum + + enum.value = int(en.getAttribute("value"), 16) + +def parse_feature(feat): + api = feat.getAttribute("api") + if api=="gl": + version = feat.getAttribute("number") + if version: + version = map(int, version.split('.')) + else: + version = None + + commands = get_nested_elements(feat, "require/command") + enums = get_nested_elements(feat, "require/enum") + for t in itertools.chain(commands, enums): + name = t.getAttribute("name") + thing = things.get(name) + if thing: + thing.version = version + + if feat.getAttribute("name")=="MSPGL_REMOVE": + commands = get_nested_elements(feat, "remove/command") + enums = get_nested_elements(feat, "remove/enum") + for t in itertools.chain(commands, enums): + name = t.getAttribute("name") + if name in things: + del things[name] + +def parse_extension(ext): + ext_name = ext.getAttribute("name") + if ext_name.startswith("GL_"): + ext_name = ext_name[3:] + + supported = ext.getAttribute("supported").split('|') + if "gl" in supported: + commands = get_nested_elements(ext, "require/command") + enums = get_nested_elements(ext, "require/enum") + for t in itertools.chain(commands, enums): + name = t.getAttribute("name") + thing = things.get(name) + if thing: + thing.extension = ext_name + def parse_file(fn): doc = xml.dom.minidom.parse(fn) root = doc.documentElement + commands = get_nested_elements(root, "commands/command") for cmd in commands: - name = get_text_contents(get_nested_elements(cmd, "proto/name")[0]) - func = funcs.get(name) - if not func: - func = Function(name) - funcs[name] = func - - aliases = cmd.getElementsByTagName("alias") - for a in aliases: - func.aliases.append(a.getAttribute("name")) + parse_command(cmd) - vec = cmd.getElementsByTagName("vecequiv") - if vec: - func.vectorequiv = vec[0].getAttribute("name") + enums = get_nested_elements(root, "enums/enum") + for en in enums: + parse_enum(en) - features = root.getElementsByTagName("feature") + features = get_nested_elements(root, "feature") for feat in features: - api = feat.getAttribute("api") - if api=="gl": - version = feat.getAttribute("number") - - commands = get_nested_elements(feat, "require/command") - for c in commands: - name = c.getAttribute("name") - func = funcs.get(name) - if func: - func.version = version - - if feat.getAttribute("name")=="MSPGL_REMOVE": - commands = get_nested_elements(feat, "remove/command") - for c in commands: - name = c.getAttribute("name") - if name in funcs: - del funcs[name] + parse_feature(feat) extensions = get_nested_elements(root, "extensions/extension") for ext in extensions: - ext_name = ext.getAttribute("name") - if ext_name.startswith("GL_"): - ext_name = ext_name[3:] - supported = ext.getAttribute("supported").split('|') - if "gl" in supported: - commands = get_nested_elements(ext, "require/command") - for c in commands: - name = c.getAttribute("name") - func = funcs.get(name) - if func: - func.category = ext_name + parse_extension(ext) parse_file("gl.xml") parse_file("gl.fixes.xml") -for f in funcs.itervalues(): - if f.category==ext or f.category in secondary: - for a in f.aliases: - aliasfunc = funcs.get(a) - if aliasfunc: - aliasfunc.extfunc = f - -def is_relevant(f): - if f.category==ext and not f.aliases: +### Additional processing ### + +# Find aliases for enums +enums = [t for t in things.itervalues() if t.kind==Thing.ENUM] +core_enums_by_value = dict((e.value, e) for e in enums if e.version) + +for e in enums: + if e.kind==t.ENUM and e.extension: + ce = core_enums_by_value.get(e.value) + if ce and ce!=e: + e.aliases.append(ce.name) + +# Create references from core things to their extension counterparts +for t in things.itervalues(): + if t.extension==target_ext or t.extension in secondary: + for a in t.aliases: + alias = things.get(a) + if alias: + alias.source = t + +def is_relevant(t): + # Unpromoted extension things are relevant + if t.extension==target_ext and not t.aliases: return True - if f.extfunc: - e = f.extfunc - if e.category==ext or e.category in secondary: + + # Core things promoted from the extension are also relevant + if t.source: + e = t.source + if e.extension==target_ext or e.extension in secondary: return True + return False -funcs = [f for f in funcs.itervalues() if is_relevant(f)] +funcs = [t for t in things.itervalues() if t.kind==Thing.FUNCTION and is_relevant(t)] funcs.sort(key=(lambda f: f.name)) +enums = filter(is_relevant, enums) +enums.sort(key=(lambda e: e.value)) -for f in funcs: - if not ver: - ver = f.version +for t in itertools.chain(funcs, enums): + if not core_version: + core_version = t.version - if f.category and not f.name.endswith(exttype): - bp_ext = f.category + # Things in backport extensions don't acquire an extension suffix + if t.extension and not t.name.endswith(ext_type): + backport_ext = t.extension - if f.extfunc: - f.typedef = "PFN%sPROC"%f.extfunc.name.upper() +for f in funcs: + if f.source: + # Typedefs for early core functions are not available in all + # implementations + f.typedef = "PFN%sPROC"%f.source.name.upper() else: f.typedef = "PFN%sPROC"%f.name.upper() -if ver: - ver = map(int, ver.split('.')) +### Output ### out = file(out_base+".h", "w") -out.write("#ifndef MSP_GL_%s_\n"%ext.upper()) -out.write("#define MSP_GL_%s_\n"%ext.upper()) +out.write("#ifndef MSP_GL_%s_\n"%target_ext.upper()) +out.write("#define MSP_GL_%s_\n"%target_ext.upper()) out.write(""" #include @@ -176,14 +271,29 @@ out.write(""" namespace Msp { namespace GL { + """) -if funcs: - out.write("\n") -for f in funcs: - out.write("extern %s %s;\n"%(f.typedef, f.name)) +if funcs or enums: + if funcs: + out.write("#if defined(__APPLE__) || !defined(GL_%s)\n"%target_ext) + for f in funcs: + out.write("typedef %s (*%s)(%s);\n"%(f.return_type, f.typedef, ", ".join(f.params))) + out.write("#endif\n\n") -out.write("\nextern Extension %s;\n"%ext) + if enums: + if core_version: + out.write("#ifndef GL_VERSION_%s\n"%"_".join(map(str, core_version))) + else: + out.write("#ifndef GL_%s\n"%target_ext) + for e in enums: + out.write("#define %s 0x%04X\n"%(e.name, e.value)) + out.write("#endif\n\n") + + for f in funcs: + out.write("extern %s %s;\n"%(f.typedef, f.name)) + +out.write("extern Extension %s;\n"%target_ext) out.write(""" } // namespace GL @@ -193,41 +303,52 @@ out.write(""" """) out = file(out_base+".cpp", "w") -out.write("#include \"%s.h\"\n"%ext.lower()) +out.write("#include \"%s.h\"\n"%target_ext.lower()) +if funcs: + out.write(""" +#ifdef __APPLE__ +#define GET_PROC_ADDRESS(x) ::x +#else +#define GET_PROC_ADDRESS(x) get_proc_address(#x) +#endif +""") out.write(""" namespace Msp { namespace GL { + """) -if funcs: - out.write("\n") for f in funcs: out.write("%s %s = 0;\n"%(f.typedef, f.name)) -out.write("\nExtension::SupportLevel init_%s()\n{\n"%ext.lower()) -if ver: - out.write("\tif(is_version_at_least(%d, %d)"%tuple(ver)) - if bp_ext: - out.write(" || is_supported(\"GL_%s\")"%bp_ext) +out.write("\nExtension::SupportLevel init_%s()\n{\n"%target_ext.lower()) +out.write("#ifdef GL_%s\n"%target_ext) +if core_version: + out.write("\tif(is_version_at_least(%d, %d)"%tuple(core_version)) + if backport_ext: + out.write(" || is_supported(\"GL_%s\")"%backport_ext) out.write(")\n\t{\n") - for f in funcs: - out.write("\t\t%s = reinterpret_cast<%s>(get_proc_address(\"%s\"));\n"%(f.name, f.typedef, f.name)) + if funcs: + for f in funcs: + out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS(%s));\n"%(f.name, f.typedef, f.name)) out.write("\t\treturn Extension::CORE;\n") out.write("\t}\n") -if ext!=bp_ext: - out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(ext)) - for f in funcs: - n = f.name - if f.extfunc: - n = f.extfunc.name - out.write("\t\t%s = reinterpret_cast<%s>(get_proc_address(\"%s\"));\n"%(f.name, f.typedef, n)) +if target_ext!=backport_ext: + out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(target_ext)) + if funcs: + for f in funcs: + n = f.name + if f.source: + n = f.source.name + out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS(%s));\n"%(f.name, f.typedef, n)) out.write("\t\treturn Extension::EXTENSION;\n") out.write("\t}\n") +out.write("#endif\n") out.write("\treturn Extension::UNSUPPORTED;\n") out.write("}\n") -out.write("\nExtension %s(\"GL_%s\", init_%s);\n"%(ext, ext, ext.lower())) +out.write("\nExtension %s(\"GL_%s\", init_%s);\n"%(target_ext, target_ext, target_ext.lower())) out.write(""" } // namespace GL